Weblogs Código

Blog Bitix

La controversia sobre las excepciones checked y uncheked

abril 20, 2018 03:00

Java

Las excepciones son una forma de gestionar las condiciones de error que se dan en los programas. En el lenguaje C se utiliza el valor de retorno de la función para determinar la condición de error que se ha producido, el problema es que comprobar el valor de retorno puede ignorarse y la gestión de errores está mezclada con la tarea del programa.

El lenguaje Java utiliza un mecanismo de excepciones, las excepciones son objetos que se lanzan cuando se produce una condición de error. Todas las excepciones en Java heredan de Throwable subdividiéndose en Error y Exception, las primeras son condiciones de error del sistema y las segundas condiciones de error del programa. A su vez las Exception pueden ser checked si heredan de esta y son aquellas que el compilador fuerza a que sean capturadas no pudiendo ignorarse, han de capturarse en una construcción try catch o declarar que el método puede lanzar la excepción no capturada. Las excepciones uncheked heredan de RuntimeException que heredan a su vez de Exception pero tienen la particularidad de que no es necesario capturarlas ni declararlas como que se pueden lanzar debido a que se consideran condiciones de error en la programación como un acceso a un array fuera de rango que produce un ArrayIndexOutOfBounds, el conocido NullPointerException cuando se utiliza una referencia nula, otro es ArithmeticException que se produce al dividir por 0.

Hay una cierta polémica sobre si las excepciones checked son una buena idea. Entre los motivos que se alegan en contra de su uso están que cambiar la firma de un método añadiendo una nueva excepción como lanzable hace que el código que usase ese método podría ocasionar errores de compilación y que hace necesario el tratarla o declararla en la cadena de métodos hasta que sea tratada. Otro motivo es que a mayor nivel en la jerarquía de llamada en los métodos se necesitarán manejar una lista amplia de excepciones.

En el lado contrario las excepciones se consideran que son buenas porque conocer las condiciones de error o excepción que puede lanzar el método forma parte de la firma del método y es necesario para realizar un correcto manejo de errores. Las excepciones que heredan de RuntimeException no se obliga a controlarlas ya que son errores producidos por un error en la programación.

Las excepciones checked pueden parecer un incordio pero son necesarias para hacer un correcto manejo de errores y evitar que el programa falle por no capturarlas. Por otro lado no deberían silenciarse con un bloque catch vacío sin una buena razón.

En el siguiente código se observa como capturar, lanzar y declarar excepciones en las firmas de los métodos en Java en una construcción try catch finally.

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

Adrianistán

Natural Language Understanding con Snips NLU en Python

abril 17, 2018 12:57

Uno de los campos más importantes de la inteligencia artificial es el del tratamiento del lenguaje natural. Ya en 1955, en el primer evento sobre Inteligencia Artificial, y promovido entre otros por John McCarthy (creador de Lisp) y Claude Shannon (padre de la teoría de la información y promotor del uso del álgebra de boole para la electrónica), estas cuestiones entraron en el listado de temas.

En aquella época se era bastante optimista con las posibilidades de describir el lenguaje natural (inglés, español, …) de forma precisa con un conjunto de reglas de forma similar a las matemáticas. Luego se comprobó que esto no era una tarea tan sencilla.

Hoy día, es un campo donde se avanza mucho todos los días, aprovechando las técnicas de machine learning combinadas con heurísticas propias de cada lenguaje.

Natural Language Understanding nos permite saber qué quiere decir una frase que pronuncia o escribe un usuario. Existen diversos servicios que provee de esta funcionalidad: IBM Watson, Microsoft LUIS y también existe software libre, como Snips NLU.

Snips NLU es una librería hecha en Rust y con interfaz en Python que funciona analizando el texto con datos entrenados gracias a machine learning y da como resultado un intent, o significado de la frase y el valor de los slots, que son variables dentro de la frase.

¿Qué tiempo hará mañana en Molina de Aragón?

Y Snips NLU nos devuelve:

  • intent: obtenerTiempo
  • slots:
    • cuando: mañana
    • donde: Molina de Aragón

Pero para esto, antes hay que hacer un par de cosas.

Instalar Snips NLU

Instala Snips NLU con Pipenv (recomendado) o Pip:

pipenv install snips-nlu

pip install snips-nlu

 

Datos de entrenamiento

En primer lugar vamos a crear un listado de frases que todas expresen la intención de obtener el tiempo y lo guardamos en un fichero llamado obtenerTiempo.txt. Así definimos un intent:

¿Qué tiempo hará [cuando:snips/time](mañana) en [donde:localidad](Molina de Aragón)?
¿Qué tal hará [cuando:snips/time](pasado mañana) en [donde:localidad](Ponferrada)?
¿Qué temperatura habrá [cuando:snips/time](mañana) en [donde:localidad](Frías)?

La sintaxis es muy sencilla. Cada frase en una línea. Cuando una palabra forme parte de un slot, se usa la sintaxis [NOMBRE SLOT:TIPO](texto). En el caso de [donde:localidad](Frías). Donde es el nombre del slot, localidad es el tipo de dato que va y Frías es el texto original de la frase. En el caso del slot cuando, hemos configurado el tipo como snips/time que es uno de los predefinidos por Snips NLU.

Creamos también un fichero llamado localidad.txt, con los posibles valores que puede tener localidad. Esto no quiere decir que no capture valores fuera de esta lista, como veremos después, pero tienen prioridad si hubiese más tipos. También se puede configurar a que no admita otros valores, pero no lo vamos a ver aquí.

Burgos
Valladolid
Peñaranda de Bracamonte
Soria
Almazán
Íscar
Portillo
Toro
Fermoselle
Sahagún
Hervás
Oña
Saldaña
Sabiñánigo
Jaca

Ahora generamos un fichero JSON listo para ser entrenado con el comando generate-dataset.

generate-dataset --language es --intent-files obtenerTiempo.txt --entity-files localidad.txt > dataset.json

Entrenamiento

Ya estamos listos para el entrenamiento. Creamos un fichero Python como este y lo ejecutamos:

import io
import json
from snips_nlu import load_resources, SnipsNLUEngine

load_resources("es")

with io.open("dataset.json") as f:
    dataset = json.load(f)

engine = SnipsNLUEngine()

engine.fit(dataset)

engine_json = json.dumps(engine.to_dict())
with io.open("trained.json",mode="w") as f:
    f.write(engine_json)

El entrenamiento se produce en fit, y esta tarea puede tardar dependiendo del número de datos que metamos. Una vez finalizado, generama un fichero trained.json con el entrenamiento ya realizado.

Hacer preguntas

Ha llegado el momento de hacer preguntas, cargando el fichero de los datos entrenados.

import io
import json
from snips_nlu import SnipsNLUEngine, load_resources

load_resources("es")

with io.open("trained.json") as f:
    engine_dict = json.load(f)

engine = SnipsNLUEngine.from_dict(engine_dict)

phrase = input("Pregunta: ")

r = engine.parse(phrase)
print(json.dumps(r, indent=2))

Ahora sería tarea del programador usar el valor del intent y de los slots para dar una respuesta inteligente.

Te animo a que te descargues el proyecto o lo hagas en casa e intentes hacerle preguntas con datos retorcidos a ver qué pasa y si guarda en los slots el valor correcto.

La entrada Natural Language Understanding con Snips NLU en Python se publicó primero en Adrianistán.

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

Variable not found

¿Aún usas ToString() para obtener el nombre de los elementos de un enum?

abril 17, 2018 11:50

C#Va un truquillo muy rápido que, aparte de al que os habla, quizás a alguno más os provoque un momento “ahh, pues claro, cómo no se me había ocurrido antes” ;)

Y es que el problema con las costumbres es que son difíciles de quitar; por ejemplo, probablemente muchos estamos acostumbrados a obtener el nombre de los miembros de un enum de la siguiente forma:
public enum Color { Red, Green, Blue }
static void Main(string[] args)
{
Console.WriteLine(Color.Red.ToString());
// Output: Red
}
A priori es correcto: llevamos años haciéndolo así y no nos ha ido mal del todo. Bueno, o sí, pero probablemente no por este motivo ;)

Aun a sabiendas de que el operador nameof existe desde hace ya bastante tiempo y habiéndolo utilizado en muchas ocasiones, a veces la costumbre hace que no nos planteemos otros casos de uso, como con los enum que veíamos arriba.

El siguiente código, totalmente equivalente al anterior, muestra cómo podemos utilizar este operador para obtener el nombre del miembro:
public enum Color { Red, Green, Blue }
static void Main(string[] args)
{
Console.WriteLine(nameof(Color.Red));
// Output: Red
}
Fijaos que, además de que sigue siendo tipado fuerte, acabamos de conseguir un microbeneficio adicional: nos hemos llevado a tiempo de compilación (porque, recordad, nameof se resuelve en compilación) la obtención del nombre, por lo que el rendimiento será mejor que la llamada a ToString(), que es resuelta en tiempo ejecución.

Publicado en Variable not found.

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

xailer.info

Lanzamiento de Xailer 5.1.0

abril 16, 2018 05:45

Estimados usuarios de Xailer,

Hoy publicamos una nueva actualización de Xailer, la versión 5.1.0 que básicamente corrige todos los errores encontrados hasta la fecha y se prepara internamente para el salto inminente a Xailer 6 que incorporará la última versión de Harbour, MinGW, SQLite, MySQL, MariaDB y Scintilla.  Más información en los siguientes enlaces:

https://www.xailer.com/?lonuevo
http://www2.xailer.com/download/?es&file=1

Un cordial saludo
[El equipo de Xailer]

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

Variable not found

Enlaces interesantes 317

abril 16, 2018 06:55

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

.NET / .NET Core

ASP.NET / ASP.NET Core

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

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

Blog Bitix

Prompt de la terminal personalizado en carpetas de git con el intérprete Bash

abril 13, 2018 10:30

GNU
Linux

Uno de los sistemas de control de versiones más utilizado es Git. Bash es el intérprete de comandos por defecto en la mayoría de distribuciones GNU/Linux. A la hora de trabajar en la terminal y estando como directorio actual en un directorio que está bajo el control de versiones de git bash por defecto no muestra ninguna información del estado de los archivos en su repositorio en el símbolo del sistema o prompt.

El intérprete Zsh y Oh-My-Zsh ofrece mediante sus temas soporte para los repositorios de git modificando el símbolo del sistema para mostrar más información acerca del estado. En Bash también es posible añadir soporte para que muestre información como la rama actual en la que se está trabajando, si hay archivos modificados o no añadidos al control de versiones, si hay archivos en el stash y una comparación entre la rama actual y la del origen o upstream.

Prompt de la terminal por defecto y en carpeta de git
  • * la presencia de este caracter indica que hay cambios en alguno de los archivos bajo el control de versiones.
  • + indica que hay archivos añadidos al stash
  • = indica que la rama está en el mismo estado que en upstream, en su lugar puede mostrarse el caracter > para indicar que la rama en local está por delante de la rama en remoto o mostrarse < para lo contrario.

El script necesario para añadir el soporte a repositorios git en Bash es git-prompt.sh. Una vez descargado su funcionalidad se personaliza con varias variables de entorno tal y como está documentado en el comentario al inicio de este script que se añaden en el archivo de perfil del usuario de inicio .bashrc. Añadidas unas variables de entorno que empiezan por GIT_PS1 y hecho el source del script junto con la utilización de la variable PROMPT_COMMAND en lugar de PS1 para posibilitar la información de estado con colores al estar en un directorio git se muestra el prompt del ejemplo anterior.

Este es el archivo .bashrc completo de la distribución Arch Linux con el soporte para el script git-prompt.sh y algunas opciones personalizadas.

La documentación completa con todas las opciones de personalización están en las primeras líneas de comentario del script.

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

Adrianistán

Introducción a Prolog, tutorial en español

abril 12, 2018 10:16

Prolog es un lenguaje de programación lógico, quizá uno de los más populares de este paradigma ya que fue el primero en implementarlo, en el año 1972 en Francia.

Durante un tiempo, se creyó que PROLOG supondría la revolución de los lenguajes de programación, siendo uno de los estandartes de los lenguajes de programación de quinta generación. Tanto se creía que Borland, la famosa empresa de compiladores para MS-DOS, tenía Turbo Prolog, junto a Turbo C++, Turbo Pascal, Turbo Assembler y Turbo Basic.

Desafortunadamente, Prolog no triunfó como se esperaba y solo fue usado dentro del mundo de la Inteligencia Artificial. Existe un estándar ISO sobre Prolog (al igual que Ada, C++ y otros lenguajes estandarizados) pero no es demasiado influyente. Tampoco ha habido ningún éxito en alguna de las versiones propuestas para dotarle de orientación a objetos al lenguaje.

Prolog sin embargo ha influenciado a algunos lenguajes como Erlang, que toman algunos aspectos de él.

No obstante, Prolog sigue siendo un lenguaje muy interesante, diferente al resto de lenguajes (tanto imperativos, como funcionales), así que pongámonos a ello.

Actualmente existen varios compiladores de Prolog: SWI Prolog, GNU Prolog, Visual Prolog (al mucha gente no lo considera Prolog de verdad), …

La mejor versión bajo mi punto de vista es SWI Prolog, que tiene una librería de predicados bastante extensa. Es rápido y permite generar ejecutables nativos (realmente no lo son, pero la máquina virtual de Prolog ocupa muy poco y apenas se nota en el tamaño del ejecutable).

Lo podéis descargar gratuitamente desde su página oficial que como curiosiad, está hecha en SWI Prolog. También está en la paquetería de las distribuciones GNU/Linux habituales.

Nuestro primer programa

Para empezar con Prolog voy a tomar un camino distinto de muchos tutoriales y voy a empezar haciendo un programa con Entrada/Salida y que se ejecute como un binario independiente. La potencia de Prolog no está ahí especialmente, pero es un buen punto de partida

Para ello definimos un predicado main de la siguiente forma y lo guardamos en un fichero main.pl.

main :- 
	write("Hola Mundo"),
	nl,
	write("¿Cuál es tu nombre? "),
	read_string(user_input,['\n'],[],_,Nombre),
	write("Hola "),write(Nombre),nl,
	halt.

¿Qué hace el programa? Imprime en pantalla Hola Mundo (write), una nueva línea (nl), lee un string de teclado con el separador \n y lo unifica con la variable Nombre. Esto ya veremos que significa, pero de momento puedes pensar que Nombre es una variable de salida y que a partir de ahí Nombre tiene un valor establecido.

Compilamos con el siguiente comando:

swipl --goal=main --stand_alone=true -o main -c main.pl

Con esto le decimos a SWI Prolog que el objetivo a demostrar es main y que nos genere un fichero stand_alone (independiente).

Y ejecutamos el fichero ejecutable como uno más.

Ahora que ya sabemos como se generan programas compilados, vamos a introducirnos más en lo que hace especial a Prolog.

La terminal de Prolog

Prolog fue diseñado con una terminal interactiva en mente. La idea era que el usuario fuese introduciendo preguntas y el programa en Prolog fuese contestando. Este enfoque, similar a usar un programa desde el REPL de tu lenguaje, no ha acabado cuajando, pero es necesario pasar por él. Más adelante veremos como con SWI Prolog no hace falta usar la terminal. La terminal se abre escribiendo swipl en la línea de comandos:

Vemos un símbolo de interrogación. Eso nos permite saber que estamos en una terminal de Prolog. Podemos escribir write(“Hola”). y tener nuestro hola mundo tradicional, aunque no es muy interesante, pero sí es muy interesante que después escribe true. Más adelante veremos por qué.

Los programas Prolog

En Prolog los programas son algo diferentes a lo que estamos acostumbrados. Realmente en Prolog no hay programas sino una base de datos. Un programa se compone de predicados, muy parecidos a los del Cálculo de Predicados. Los predicados aportan información sobre las relaciones entre elementos. Todos los predicados tienen que acabar en punto.

Siguiendo las mismas normas que el cálculo de predicados:

  • Las constantes empiezan por minúscula
  • Las variables empiezan por mayúscula
  • Las funciones son constantes seguidas de N teŕminos. Son funciones estrictamente matemáticas.
  • Los predicados pueden ser atómicos o compuestos, con operadores lógicos (and, or, implica, etc)

Prolog durante la ejecución, va a intentar demostrar que el predicado es cierto, usando el algoritmo de backtracking. Y ahí está la verdadera potencia de Prolog. Veamos unos ejemplos:

fruta(manzana).
fruta(naranja).
fruta(platano).

Guarda ese archivo con extensión .pl y ejecuta swipl comida.pl.

Ahora en la terminal podemos hacer preguntas. ¿Es la manzana una fruta? Prolog responde verdadero. ¿Es la pera una fruta? Prolog responde que falso, porque según el archivo comida.pl, no lo es. Prolog no es inteligente, no sabe que significan las palabras, simplemente actúa siguiendo un conjunto de normas formales.

Hemos dicho que Prolog tiene variables. Una variable en Prolog es un marcador de hueco, es algo que no existe, porque no es ninguna constante en específico. Veamos la potencia de las variables con este otro predicado.

En este caso pedimos demostrar fruta(X).. Prolog buscará la primera solución que demuestra el predicado, que es que X valga manzana. Aquí podemos pulsar ENTER y Prolog se para o pulsar N y Prolog busca otra solución. ¿Potente, verdad? Prolog realiza un proceso interno que se llama unificación, es importante saber como funciona para ver que hace Prolog en realidad.

Unificación

La unificación es un proceso que combina dos predicados en uno que encaja. Para ello buscamos las sustituciones de valores con los que dos predicados son compatibles (realmente solo se pueden modificar las variables). No obstante, Prolog busca siempre el unificador más general, que es aquel que unifica dejando los predicados de forma más genérica posible, es decir, que pueden usarse con más valores.

Espero que esta imagen aclare el concepto de unificación. Básicamente Prolog para intentar demostrar un predicado intentará unificar con otros predicados del programa. Así cuando ponemos por ejemplo comida(manzana) , unifica con comida(X) así que Prolog toma ese predicado para continuar.

Backtracking

Cuando Prolog intenta demostrar un predicado aplica el algoritmo de backtracking. Este algoritmo recorre todas las soluciones posibles pero de forma más inteligente que la fuerza bruta. Backtracking intenta conseguir una solución hasta que un predicado falla, en ese momento, Prolog va hacia atrás y continúa por otra vía que pueda seguir.

Cada predicado es un nodo. Si un predicado falla se vuelve atrás. Esto es muy interesate ya que Prolog técnicamente puede ejecutar código hacia atrás.

Un predicado Prolog sigue esta estructura:

Predicados avanzados

Pero los predicados de Prolog no tienen por qué ser así de simples. Normalmente se usa el operador :- para indicar algo que para que se cumpla la parte de la izquierda, tiene que cumplirse la parte de la derecha antes (en cálculo de predicados es ←).

Por ejemplo, todas las frutas son comidas, así que podemos añadir esto a nuestro archivo.

fruta(manzana).
fruta(naranja).
fruta(platano).

comida(X) :- fruta(X).

Y los predicados en Prolog se pueden repetir y repetir y repetir. Prolog siempre intenta demostrar de arriba a abajo, si falla un predicado, prueba con el siguiente más para abajo y termina cuando no hay más predicados que probar. ¡Así que podemos definir comida en base a más predicados!

fruta(manzana).
fruta(naranja).
fruta(platano).

carne(pollo).
carne(vaca).
carne(cerdo).
carne(caballo).

comida(paella).
comida(pulpo).

comida(X) :- fruta(X).
comida(X) :- carne(X).

Operaciones

En Prolog existen varios operadores importantes:

  • , (coma) AND
  • ; (punto y coma) OR
  • A = B, se intenta unificar A y B. Devuelve true si funciona
  • A \= B es falso si A y B unifican
  • A is B, se evalúa B (es decir, se calcula lo que representa) y se unifica con A
  • A =:= B , evalúa A, evalúa B y los compara. Verdadero si son iguales
  • A =\= B, evalúa A, evalúa B y los compara. Falso si son iguales
  • Y muchos otros como =<, >=, >, < que tienen el comportamiento esperado.
  • Las operaciones matemáticas solo se pueden introducir en expresiones que vayan a ser evaluadas.

Quiero prestar especial atención en símbolo de igual que no es asignación sino unificación, pero puede parecerse. Estas dos líneas son equivalentes:

X = 5
% y 
5 = X

Ya que en ambos casos se unifica X con 5.

Veamos un ejemplo de todo esto, ya mucho más realista.

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Programa restaurante  %
%%%%%%%%%%%%%%%%%%%%%%%%%%%	

% menu

entrada(paella).
entrada(gazpacho).
entrada(pasta).

carne(filete_de_cerdo).
carne(pollo_asado).

pescado(trucha).
pescado(bacalao).

postre(flan).
postre(nueces_con_miel).
postre(naranja).

% Valor calorico de una racion

calorias(paella, 200).
calorias(gazpacho, 150).
calorias(pasta, 300).
calorias(filete_de_cerdo, 400).
calorias(pollo_asado, 280).
calorias(trucha, 160).
calorias(bacalao, 300).
calorias(flan, 200).
calorias(nueces_con_miel, 500).
calorias(naranja, 50).

% plato_principal(P) P es un plato principal si es carne o pescado

plato_principal(P):- carne(P).
plato_principal(P):- pescado(P).

% comida(Entrada, Principal, Postre)

comida(Entrada, Principal, Postre):-
        entrada(Entrada),
        plato_principal(Principal),
        postre(Postre).
    
% Valor calorico de una comida

valor(Entrada, Principal, Postre, Valor):-
        calorias(Entrada, X),
        calorias(Principal, Y),
        calorias(Postre, Z),
        sumar(X, Y, Z, Valor).

% comida_equilibrada(Entrada, Principal, Postre)

comida_equilibrada(Entrada, Principal, Postre):-
        comida(Entrada, Principal, Postre),
        valor(Entrada, Principal, Postre, Valor),
        menor(Valor, 600).


% Conceptos auxiliares

sumar(X, Y, Z, Res):-
        Res is X + Y + Z.             % El predicado "is" se satisface si Res se puede unificar
                                      % con el resultado de evaluar la expresion X + Y + Z 
menor(X, Y):- 
        X < Y.                        % "menor" numerico

dif(X, Y):-
        X =\= Y.                      % desigualdad numerica 


% cuantas comidas llevan naranja de postre
%

comidas_con_naranja :-
	write("Comidas con naranja: "),
	aggregate_all(count,comida(_,_,naranja),X),
	write(X),
	nl.

Lo cargamos con swipl restaurante.pl y podemos contestar a las siguientes preguntas de forma sencilla:

¿Qué valor calórico tiene la comida de paella, trucha y flan?

valor(paella,trucha,flan,N).

Dime una comidas equilibrada que lleve naranja de postre

comida_equilibrada(X,Y,Z),Z=naranja.

¿Cuántas comidas con naranja hay?

comidas_con_naranja.

Variables anónimas y predicados predefinidos

Si te fijas en el predicado comidas_con_naranja, es diferente al resto. Esta programado de otra forma. La salida por pantalla se hace con write como ya habíamos visto al principio, write es un predicado que siempre es cierto y en caso de backtracking simplemente pasa. aggregate_all es también otro predicado incluido en SWI Prolog, para en este caso, contar cuantas soluciones tiene el predicado comida(_,_,naranja). X unifica en aggregate_all con el valor que toca (que es una constante, los números son constantes) y en las siguientes sentencias (write), X ha sido sustituido por el valor con el que unificó en aggregate_all.

Por otro lado, ¿qué significa la barra baja? Es una variable anónima. Cuando no usamos una variable en más lugares y no nos interesan sus valores podemos simplemente poner barra baja.

Listas en Prolog

Prolog tiene un tipo de dato más avanzado, las listas. Su tamaño es dinámico y es conveniente distinguir la cabeza de la cola. La cabeza es el primer elemento de una lista, la cola el resto de la lista.

Las listas se crean con corchetes:

X = [1,2,3,4,5],
sumlist(X,N).

sumlist es un predicado de SWI que hace la suma de todos los elementos de una lista.

Con la barra podemos separar cabeza y cola de una lista:

[1,2,3,4] = X,
[H|T] = X.

Implementando sumlist

Vamos a ver como se puede implementar sumlist con Prolog de forma sencilla.

sumar([],0).
sumar([H|T],N) :-
	sumar(T,X),
	N is X+H.

El predicado es sencillo, para un caso base de lista vacía, la suma es 0. Para otros casos más complejos separamos la lista en cabeza H y cola T y la suma es N. Esta suma se define como el resultado de sumar T (queda en X) y la cabeza H.

Assert y retract

¿Podemos crear predicados en tiempo real? Claro. Prolog provee de los predicados especiales assert para añadir y retract para eliminar un predicado.

Operador de corte

Prolog tiene un operador muy controvertido, el operador de corte, !. Se trata de un operador que permite no volver hacia atrás. Hay que intentar no usarlo, pero muchas veces mejora el rendimiento.

Metaprogramación

Prolog tiene un gran soporte para la metaprogramación. Assert y Retract son ya formas de metaprogramación, no obstante Prolog tiene muchas más.

call permite ejecutar código Prolog desde Prolog.

setarg permite modificar un término de un predicado y arg unifica una variable con el término de un predicado que queramos. nb_setarg es la versión de setarg que en caso de backtracking no deshace la operación. Un ejemplo de esto lo podemos encontrar en la definición de aggregate_all en la librería de SWI Prolog:

aggregate_all(count, Goal, Count) :-
    !,
    aggregate_all(sum(1), Goal, Count).
aggregate_all(sum(X), Goal, Sum) :-
    !,
    State = state(0),
    (  call(Goal),
           arg(1, State, S0),
           S is S0 + X,
           nb_setarg(1, State, S),
           fail
    ;  arg(1, State, Sum)
).

 

Debug con trace

Prolog posee un predicado muy útil para hacer debugging. Es trace y con el predicado que vaya a continuación podremos inspeccionar todas las operaciones del motor de backtracking.

La entrada Introducción a Prolog, tutorial en español se publicó primero en Adrianistán.

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

Picando Código

Actualización a Montevideo Bicis con datos de accidentes 2017

abril 10, 2018 01:00

Montevideo Bicis es un sitio web que presenta información objetiva para gente que quiera circular en bicicleta en Montevideo. Aprovecha Datos Abiertos de la Intendencia de Montevideo y y UNASEV. Después de un buen tiempo, UNASEV liberó los datos de accidentes de tránsito de 2017. Como era de esperarse, el archivo es inconcistente con los csv liberados años anteriores… Pero bueno, por lo menos los datos están y son procesables por lenguaje de máquina.

El proceso fue más o menos el mismo que para los datos de 2016, y ya quedó actualizado en el sitio. Otra pequeña mejora que le hice fue convertir a Float los números de los accidentes que ocurrieron con bicicleta, para que el porcentaje sobre el total sea más preciso. Pueden visitar la página de accidentes para ver la nueva información. La cantidad total de muertes registradas en accidentes de tránsito subió un poco respecto al año anterior, pero la cantidad de accidentes que involucraron bicicletas bajó.

Montevideo Bicis

Ojalá algún día Montevideo se convierta en una ciudad amigable para los ciclistas… Si les interesa el tema, pueden visitar MontevideoBicis.com, y ver el código fuente en GitHub. Y si tienen ideas o críticas sobre el sitio, son más que bienvenidos a compartirlos en los comentarios de este post.

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

Variable not found

Cómo incluir scripts en la página desde vistas parciales ASP.NET Core MVC con DynamicSections

abril 10, 2018 06:55

ASP.NET CoreCuando desarrollamos una aplicación ASP.NET Core MVC, es muy frecuente encontrar que nuestras vistas definen secciones de contenido usando la directiva @section que más adelante se incluyen en el Layout para formar parte de la información enviada al lado cliente.

Sin embargo, ya sabemos que no es posible utilizar secciones en vistas parciales o cualquier otro tipo de componentes, lo cual complica algunos escenarios.

Por ejemplo, es relativamente frecuente que en el lado servidor generemos código HTML utilizando algún mecanismo de reutilización de marcado, como vistas parciales, templated helperstag helpers, etc., y que éste requiera recursos extra como scripts o CSS que obligatoriamente deberíamos incluir en las vistas principales donde se utilicen.

Más en el terreno práctico, imaginad que creamos una vista parcial que requiere que las páginas donde vayamos a usarla incluyan una referencia a un archivo de scripts y un bloque de inicialización como el siguiente:
@* Partial view: _MyComponent.cshtml *@
<div class="my-component">
<!-- UI goes here -->
</div>

<!-- And now, add dependencies and initialization code -->
<script src="path/to/my-component.js" ></script>
<link rel="stylesheet" href="path/to/my-component.css" ></script>
<script>
// Initialization code goes here
$(".my-component").setup();
</script>
Aquí es donde comienzan los problemas. Si lo enfocamos como hemos mostrado anteriormente y resulta que en una misma página podemos tener más de una instancia de dicha vista parcial, estaremos incluyendo en la página las referencias y código de inicialización más de una vez, lo cual podría traernos bastantes dolores de cabeza:
<html>
<body>
...
<!-- My Component, instance #1 -->
@Html.Partial("_MyComponent.cshtml")
...
<!-- My Component, instance #2 -->
@Html.Partial("_MyComponent.cshtml")
...
</body>
</html>
Además de problemas de rendimiento y mal funcionamiento de la aplicación, también podría ocurrir que al insertar la parcial en la página, los scripts quizás aparecerían antes de referenciar los componentes o frameworks utilizados, pues normalmente esto suele hacerse al cerrarse el <body>.

Por ejemplo, en el código anterior nuestro componente utiliza JQuery, por lo que necesitamos que este framework se cargue antes de que nuestro código aparezca en la página, cosa que no siempre podremos asegurar. Así, el código enviado a la página podría ser el siguiente:
<html>
<body>
...
<!-- My Component, instance #1 -->
<div class="my-component">
<!-- UI goes here -->
</div>
<script src="path/to/my-component.js" ></script>
<link rel="stylesheet" href="path/to/my-component.css" ></script>
<script>
// Initialization code goes here
$(".my-component").setup();
</script>
...

<!-- My Component, instance #2 -->
<div class="my-component">
<!-- UI goes here -->
</div>
<script src="path/to/my-component.js" ></script>
<link rel="stylesheet" href="path/to/my-component.css" ></script>
<script>
// Initialization code goes here
$(".my-component").setup();
</script>
...
<script src="/scripts/jquery.min.js"></script>
</body>
</html>
Obviamente, esto provocaría un error en la página.

En este post vamos a ver un posible enfoque para solucionar este escenario. La idea es bastante sencilla, pues simplemente vamos a hacer posible que cada vista parcial o componente pueda registrar código HTML que luego sea renderizado en un lugar específico de la página. El objetivo sería algo similar a lo que conseguimos con la definición de secciones @section y @RenderSection(), pero aplicable a cualquier tipo de vista parcial.

¿Qué queremos conseguir?

Creo que para tenerlo más claro, lo mejor es comenzar a explicarlo viendo lo que pretendemos obtener. La idea es que desde cualquier componente de la Vista en aplicaciones MVC podamos registrar bloques de código (scripts, CSS o lo que sea) mediante un tag helper como el siguiente:
@* _MyComponent.cshtml *@
<div class="my-component">
<!-- UI goes here -->
</div>

<register-block dynamic-section="scripts" key="my-component">
<script src="path/to/my-component.js" ></script>
<link rel="stylesheet" href="path/to/my-component.css" />
</register-block>
Observad que el sistema que vamos a crear es muy similar a las secciones que en Razor definimos de forma estática con @section y renderizamos con @RenderSection(), por lo que llamaremos a nuestro componente Dynamic Sections.
El tag helper <register-block> que veis en el código anterior no generará nada en la vista desde la que se renderice nuestra vista parcial "_MyComponent.cshtml"; simplemente irá guardando el contenido en un diccionario en memoria asociado a la sección “scripts” y bajo la clave “my-component”. Si existen en una página varias instancias de nuestro componente, en memoria sólo se registrará una vez porque todas utilizarán la misma clave y sección.

Ya desde el layout o cualquier otro punto, podemos introducir el contenido que ha ido siendo registrado mediante otro tag helper:
@* _Layout.cshtml *@
<html>
<body>
...
<dynamic-section name="scripts" />
</body>
</html>
Como podréis suponer, el tag helper <dynamic-section> renderizará el contenido asociado a la sección dinámica llamada “scripts” justo en el punto de la página en el que ha sido invocado. Ahí es donde se incluirá todo el código registrado por los distintos componentes que conforman la página.

Profundizando un poco en la idea podemos conseguir cosas bastante interesantes. Por ejemplo, jugando con la clave única del bloque de código podemos conseguir que determinados componentes incluyan en la página un código común para todas las instancias, y luego un código específico por cada instancia:
@* _MyComponent.cshtml *@
@model string
@{
var id = "c" + DateTime.Now.Ticks; // Unique id for this instance
}
<div class="my-component" id="@id">
<h3>@Model</h3>
</div>

<register-block dynamic-section="scripts" key="my-component-common">
<!-- Common initialization code for my component (generated only once) -->
</register-block>

<register-block section="scripts" key="my-component-@id">
<!-- Initialization code for @id -->
</register-block>
De esta forma, si renderizamos una vista como la siguiente, en la que se introducen dos instancias distintas del la vista parcial "_MyComponent", obtendremos el resultado mostrado justo a continuación:
@* View: Index.cshtml *@
...
<div class="jumbotron">
@Html.Partial("_MyComponent", "Hello, world")
@Html.Partial("_MyComponent", "How are u doing?")
</div>
...

<!-- Página renderizada -->
<html>
<body>
...
<div class="jumbotron">
<div class="my-component" id="c636551599516842141">
<h1>Hello, world</h1>
</div>
<div class="my-component" id="c636551599516868415">
<h1>How are u doing?</h1>
</div>
</div>
...

<!-- Common initialization code for my component (generated only once) -->
<!-- Initialization code for c636551599516842141 -->
<!-- Initialization code for c636551599516868415 -->
</body>
</html>

Implementando el core

Como podremos ver a nivel de código, el funcionamiento creo que es el más simple posible, pues aprovechamos la posibilidad que nos brinda ASP.NET Core para almacenar información personalizada en la colección HttpContext.Items. El contenido que vayamos guardando ahí persistirá exclusivamente durante la petición actual y será descartado cuando ésta finalice, por lo que parece el lugar indicado para ir almacenando los contenidos registrados mediante el tag helper <register-block> hasta que sean introducidos en la página por <dynamic-section>.
Spoiler: el código fuente del proyecto está disponible en GitHub, y también podéis usarlo directamente descargando el paquete NuGet. Al final del post tenéis más información al respecto.
Aunque hemos comentado que estas funcionalidades de registro y obtención de bloques de código estarán disponibles en forma de tag helper, con muy poco esfuerzo podríamos implementarlas también en forma de HTML helpers, por lo que vamos a crear el “core” del sistema de forma que podamos utilizarlo desde ambas opciones.
public static class DynamicSectionsHelpers
{
private static string HttpContextItemName = nameof(DynamicSectionsHelpers);

/// <summary>
/// Registers a code block in a dynamic section.
/// </summary>
public static void RegisterBlock(this HttpContext httpContext,
string dynamicSectionName, string key, string content)
{
var sections = (SectionDictionary)httpContext.Items[HttpContextItemName];
if (sections == null)
{
sections = new SectionDictionary();
httpContext.Items[HttpContextItemName] = sections;
}
dynamicSectionName = dynamicSectionName ?? string.Empty;
key = key ?? string.Empty;
if (!sections.ContainsKey(dynamicSectionName))
{
sections[dynamicSectionName] = new BlockDictionary();
}
sections[dynamicSectionName][key] = content;
}

/// <summary>
/// Gets the content of the specified dynamic section.
/// </summary>
public static string GetDynamicSection(this HttpContext httpContext,
string dynamicSectionName, bool remove = true)
{
var result = string.Empty;
var sections = (SectionDictionary)httpContext.Items[HttpContextItemName];
if (sections == null)
return result;

dynamicSectionName = dynamicSectionName ?? String.Empty;
if (dynamicSectionName == "*")
{
// Get all sections
result = GetSectionAndRemoveWhenRequested(sections, remove, sections.Keys.ToArray());
}
else if (sections.ContainsKey(dynamicSectionName))
{
// Get only the specified section
result = GetSectionAndRemoveWhenRequested(sections, remove, dynamicSectionName);
}

return result;
}

private static string GetSectionAndRemoveWhenRequested(SectionDictionary sections,
bool remove, params string[] sectionNames)
{
var sb = new StringBuilder();
foreach (var sectionName in sectionNames)
{
var contents = sections[sectionName].Select(c => c.Value);
foreach (var content in contents)
{
sb.Append(content);
}

if (remove) // This section can be obtained only once!
{
sections.Remove(sectionName);
}
}
return sb.ToString();
}

private class BlockDictionary : Dictionary<string, string>
{
public BlockDictionary() : base(StringComparer.CurrentCultureIgnoreCase) { }
}

private class SectionDictionary : Dictionary<string, BlockDictionary>
{
public SectionDictionary() : base(StringComparer.CurrentCultureIgnoreCase) { }
}
}
Creo que el código se entiende relativamente bien, pero comentaré rápidamente sus dos principales métodos, porque el resto ya son detalles de implementación:
  • El método RegisterBlock() es el encargado de registrar un contenido en una sección, utilizando la clave que le llega como parámetro.
  • El método GetDynamicSection() retorna el contenido de todos los bloques registrados en una sección determinada. Sin embargo, hemos implementado una convención que puede venir bien en algunas ocasiones: si el nombre de la sección a renderizar es “*”, se renderizarán todas las secciones registradas. También, mediante un parámetro es posible indicar si el contenido debe ser eliminado del diccionario una vez haya sido obtenido (por defecto, true).

Implementación de HTML Helpers

Partiendo de la clase anterior, que prácticamente implementa todo lo que necesitamos, crear helpers HTML que faciliten su uso desde vistas es trivial.
public static class DynamicSectionsHtmlExtensions
{
/// <summary>
/// Registers a code block in a dynamic section.
/// </summary>
public static string RegisterBlock(this IHtmlHelper helper,
string dynamicSectionName, string key, string content)
{
helper.ViewContext.HttpContext
.RegisterBlock(dynamicSectionName, key, content);
return string.Empty;
}

/// <summary>
/// Gets the content of the specified dynamic section.
/// </summary>
public static IHtmlContent DynamicSection(this IHtmlHelper helper,
string dynamicSectionName = "*", bool remove = true)
{
var blocks = helper.ViewContext.HttpContext
.GetDynamicSection(dynamicSectionName, remove);
return new HtmlString(blocks);
}
}
De esta forma, podremos hacer uso de construcciones como las siguientes para registrar un contenido:
...
@Html.RegisterBlock("scripts", "my-component", "<script>console.log('Hello, world!');</script>")
...
Y también para renderizar las secciones más adelante:
<html>
<body>
...
@Html.DynamicSection("scripts")
</body>
</html>
Recordad que para que los extensores de IHtmlHelper estén disponibles en una vista debemos importar en ella el espacio de nombres donde han sido definidos, bien mediante algo como @using DynamicSections en la propia vista, o bien de forma global en /Views/_ViewImports.cshtml.

Implementación de tag helpers

Comencemos creando el tag helper <register-block>. Como podemos observar, el código es bastante simple porque lo único que hace es renderizar el contenido de la etiqueta y llamar al método DynamicSections.RegisterBlock(), visto anteriormente, para almacenarlo. Tras ello, elimina el contenido para que no sea volcado a la página en ese momento.
[HtmlTargetElement("register-block")]
public class RegisterBlockTagHelper: TagHelper
{
[ViewContext, HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }

public string Key { get; set; }
public string DynamicSection { get; set; }

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var childContents = await output.GetChildContentAsync(useCachedResult: true);
var content = childContents.GetContent();
ViewContext.HttpContext.RegisterBlock(DynamicSection, Key, content);
output.SuppressOutput();
}
}
A continuación, veamos el tag helper <dynamic-section>, cuyo código es igual de sencillo:
[HtmlTargetElement("dynamic-section", Attributes="Name")]
public class DynamicSectionTagHelper : TagHelper
{
[ViewContext, HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }

public string Name { get; set; }
public bool Remove { get; set; }

public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.SuppressOutput();
output.Content.SetHtmlContent(ViewContext.HttpContext.GetDynamicSection(Name, Remove));
}
}
Recordad que para que los nuevos tag helpers estén disponibles en una vista debemos importarlos mediante usando la directiva como sigue, bien en la propia vista o bien de forma global en /Views/_ViewImports.cshtml:
@addTagHelper *, DynamicSections
El código anterior asume que los tag helpers han sido definidos en un ensamblado llamado DynamicSections. Si no es así, sustituid este nombre por el que hayáis usado (por ejemplo, el nombre del ensamblado principal de vuestro proyecto).

Me viene bien este código, ¿cómo lo incluyo en mi proyecto?

Lo primero, recuerda que no debes confiar en el código de extraños ;-D

Pero si es tu intención, mejor que copiarlo y pegarlo desde el blog quizás te sea más sencillo acudir a descargarlo desde el repositorio en GitHub, o utilizar directamente el paquete NuGet “DynamicSections” donde ya lo tendrás cocinado. En cualquier caso, es interesante que eches un vistazo primero a la home del proyecto en GitHub, donde encontrarás algo de documentación y algunos ejemplos de uso.

Por supuesto, feedback is welcome ;)

Publicado en Variable not found.

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

Adrianistán

Mónada ST en Haskell: STRef, STArray

abril 09, 2018 10:32

Haskell tiene una librería muy completa, con muchas estructuras de datos y, en este caso, mónadas muy interesantes. En este caso vamos a hablar de la mónada ST. ST son las siglas de State Threads. Fueron definidas por Simon Peyton-Jones en un paper de 1994 y son una forma muy curiosa que tiene Haskell de permitirnos escribir código con estructuras de datos mutables. La gracia está en que se garantiza que es imposible que la mutabilidad interna que hay dentro de la mónada ST salga al exterior, de modo que de cara al exterior son funciones puras igualmente. Esta mónada no sirve para comunicarse con el exterior como sí sirve IO pero si podemos usar ST antes que IO, mejor.

STRef

La estructura más fundamental es STRef, que permite tener una variable mutable dentro de Haskell. Las funciones que permiten su manejo son newSTRef, readSTRef, writeSTRef y modifySTRef. Creo que es bastante evidente para qué sirve cada una, pero veamos un ejemplo práctico.

Vamos a hacer una función que sume todos los elementos de una lista. Existen varias formas de hacerlo de forma pura en Haskell:

sumar :: Num a => [a] -> a
sumar [] = 0
sumar (x:xs) = x+sumar xs

Una versión recursiva

sumar :: Num a => [a] -> a
sumar = foldr1 (+)

Una versión más compacta

En un lenguaje de programación imperativo sin embargo posiblemente haríamos algo parecido a esto:

int sumar(int[] nums){
    int suma = 0;
    for(int i=0;i<nums.length;i++){
        suma += nums[i];
    }
    return suma;
}

Con ST podemos hacer código que se parezca a la versión imperativa, lo cuál es útil en determinados algoritmos y también si queremos ganar eficiencia.

import Control.Monad.ST
import Control.Monad
import Data.STRef

sumar :: Num a => [a] -> a
sumar xs = runST $ do
	x <- newSTRef 0
	
	forM_ xs $ \n -> 
		modifySTRef x $ \x -> x+n

	readSTRef x

Lo primero que tenemos que hacemos es ejecutar la mónada ST con runST y a continuación la función. Allí creamos una variable mutable con valor inicial 0. Después lanzamos forM_ que itera sobre cada elemento de la lista xs ejecutando para cada elemento la función que llama a modifySTRef que ejecuta a su vez la función que suma el valor del acumulador con el valor del elemento actual de la lista.

Por último, la función finaliza devolviendo el valor de x.

Como veis, el código no tiene nada que ver a las otras versiones de Haskell y tiene un gran parecido con la versión de Java. No obstante, el código sigue siendo puro, sin efectos colaterales.

STArray

Pero no solo tenemos STRef, también tenemos STArray que es un array de tamaño fijo con estas mismas propiedades. Las funciones básicas son newListArray, readArray, writeArray y getElems.

Por ejemplo, podemos implementar el algoritmo de Bubble Sort de forma imperativa con STArray:

import Control.Monad
import Control.Monad.ST
import qualified Data.Array.ST as ST
import Data.STRef

bubblesort :: [Int] -> [Int]
bubblesort xs = runST $ do
	let l = length xs
	temp <- newSTRef $ head xs
	array <- ST.newListArray (0,l-1) xs :: ST s (ST.STArray s Int Int)

	forM_ [0..l] $ \i -> do
		forM_ [1..(l-1)] $ \j -> do
			prev <- ST.readArray array (j-1)
			actual <- ST.readArray array j	
			if prev > actual then do
				writeSTRef temp prev
				ST.writeArray array (j-1) actual
				t <- readSTRef temp
				ST.writeArray array j t
			else do
				return ()

	ST.getElems array
			
main :: IO ()
main = do
	let orden = bubblesort [3,4,1,2]			
	putStrLn ("Orden: "++(show orden))

La mónada ST junto con las funciones de Control.Monad nos permiten escribir código que parece imperativo y con mutabilidad, sin perder la pureza y la seguridad de Haskell.

La entrada Mónada ST en Haskell: STRef, STArray se publicó primero en Adrianistán.

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

Picando Código

Entrevista en Sputnik Mundo

abril 09, 2018 10:30

A raíz del artículo que escribí para la diaria sobre Ética hacker, fui entrevistado en Sputnik Mundo. El artículo:

Hackers: ¿amigos o enemigos de los ciudadanos?
Sputnik consultó al desarrollador y hacker cívico Fernando Briano para contarte qué es el software libre, en qué consiste su ética, y por qué es la bandera de los piratas informáticos.

Una de las ideas con estos textos es aclarar la definición de hacker que generalmente se malinterpreta como ciber-criminal. Pero hablé de software libre, del derecho a reparar, privacidad y más.

Fue una entrevista por teléfono, lo que lo hizo más difícil para mí en cuanto a nervios. Pero creo que el resultado final es bastante bueno. Los invito a leer la nota, y desde acá mando un agradecimiento a Sputnik y a Angelina por la entrevista.

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

Picando Código

Daniela Vázquez: científica de datos extrae y abre datos del Parlamento Uruguayo

abril 09, 2018 09:00

Si bien Uruguay ha avanzado bastante en el tema de Datos Abiertos, todavía queda mucho por hacer. El Parlamento en particular no publica Datos Abiertos. Sí publica diarios de sesiones, pero en PDF, una de las pesadillas de los activistas de datos. No pueden ser directamente procesados en código de máquina a diferencia de formatos como CSV, JSON, txt y demás. Tampoco hay una API de dónde obtener los datos, hay que descargarlos desde el sitio web del Parlamento.

Pero esto no impidió que Daniela Vázquez obtuviera y procesara los datos. En su blog escribió “Scrapeando las Sesiones Parlamentarias de Uruguay”, donde nos cuenta detalladamente cómo programó un scraper para descargar los archivos PDF usando rvest y extrajo el texto a través de pdftools, herramientas del lenguaje de programación R. ¡Lectura muy recomendable! A pesar de no haber visto nunca nada en R, el post está muy bien explicado y me resultó muy entendible.

Este estudio desencadenó en “¿De qué se habló en el Parlamento uruguayo desde 2017?“, donde hace un análisis de los textos levantados en la entrada anterior, y presenta distintos estudios de las sesiones de Diputados y Senadores: Con qué frecuencia se reunieron, Qué tan largas fueron las sesiones, Palabras más comunes y Análisis de sentimiento.

Sentimiento en sesiones del Senado

Además de explicar cómo hizo cada estudio, su post está complementado con gráficas como la que ven en la imagen que acompaña este post. La información objetiva y clara, como debe ser para que cada uno la interprete críticamente y saque sus conclusiones.

Como si todo esto fuera poco, Daniela subió el código fuente de su trabajo a GitHub, y comparte los datos en formato CSV para las sesiones de Diputados y Senadores. Muchas gracias Daniela por compartir tu conocimiento y gran trabajo. Que haya cada vez más rebeldes de los datos 💪

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

Variable not found

Enlaces interesantes 316

abril 09, 2018 06:59

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

.NET / .NET Core

ASP.NET / ASP.NET Core

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

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

Koalite

Programar no es desarrollar

abril 09, 2018 05:06

Me encanta programar. Probablemente sea la parte de mi trabajo que más disfruto. Y creo que soy capaz de valorar la importancia de programar bien y el impacto que ello tiene en el buen desarrollo de un proyecto de software.

Recuerdo cuando, hace unos 20 años, estaba empezando la carrera de Ingeniería Informática y pensaba que programar era algo sin importancia. Algo de lo que podían ocuparse “esos de FP”, porque nosotros, los auténticos ingenieros, nos encargaríamos de la parte de análisis, diseño, gestión de proyecto y demás cosas importantes. Total, rellenar los huecos de nuestros fantásticos diseños no era muy distinto de niños coloreando sus cuadernos de dibujo, y para eso no hacía falta gente con nuestras enormes capacidades. Huelga decir que, además de ser un planteamiento arrogante que sóla la juventud y la necedad pueden sostener, estaba completamente equivocado.

Por suerte los tiempos han cambiado (al menos en parte), y ese enfoque en el que los programadores son los últimos monos, ya no está tan en boga. Es verdad que sigue habiendo reductos en los cuales la jerarquía basada en jefes de proyectos, analistas funcionales, analistas programadores, programadores, etc., se mantiene, pero me atrevería a decir que es una visión que está en declive y se está dejando de ver la programación como una tarea mecánica destinada a la gente con menos experiencia para empezar a valorarla más.

Claro que, como siempre que cambian las tornas, corremos el riesgo de irnos al otro extremo. Al de entender la programación como la parte fundamental del desarrollo de software. Y me temo que tampoco es así. Hace tiempo que dejé de creer en la separación rígida entre roles en el mundo del desarrollo de software, pero pese a ello, y sin pretender en ningún momento sonar arrogante, considero importante distinguir entre programar y desarrollar software. Entre programadores y desarrolladores de software.

Pero, ¿qué se supone que debe hacer un programador? Como mínimo, ser capaz de escribir la secuencia de pasos para resolver un problema en un lenguaje que sea capaz de interpretar una máquina. Hay gente muy buena en eso. Humanos con los que puedes hablar en lenguaje natural y se encargan de convertirlo a C, Python, o el lenguaje de turno. Y no sólo eso. Lo hacen con un código elegante, eficiente, fácil de mantener, acorde a las buenas prácticas de turno y que cumple todas las expectativas de los crafters más exigentes.

Vamos a ver un ejemplo.

Programando Bien™

Supongamos que tenemos que añadir una pequeña funcionalidad a un producto que ya existe: editar un tweet. Como somos afortunados, resulta que Twitter está desarrollado siguiendo todas las buenas prácticas de turno y su código es fácil de modificar.

OJO: esta simplificación es mentira y no tiene sentido para la escala de Twitter, pero es sólo un ejemplo.

Por supuesto, estamos usando DDD y arquitecturas poligonales con cebolla, así que nuestro código empieza por un servicio de aplicación/caso de uso tal que así:

public class TweetEditor {
  // Inyectados por constructor
  private readonly IUnitOfWork uow;
  private readonly ITweetRepository repository;

  public void EditTweet(Guid tweetId, string newContent) {
    using (var tx = uow.Start()) {
      var tweet = repository.GetById(tweetId);
      tweet.UpdateContent(newContent);
      tx.CommitChanges();
    }
  }
}

Vamos bien. Tenemos un servicio que recibe sus dependencias por constructor, utiliza una entidad de dominio, Tweet, un repositorio, y el patrón UnitOfWork. Todo muy de libro. En nuestra entidad implementamos la (simple) lógica de negocio:

public class Tweet {

  // ... todo lo que existiera antes en la entidad Tweet

  public void UpdateContent(string newContent) {
    Check.Require(!string.IsNullOrWhiteSpace(newContent));

    this.content = newContent;
  }
}

Perfecto. Lógica encapsulada en la entidad y garantizando que se mantienen los invariantes adecuados.

Desde un punto de vista de programación esta implementación es estupenda (asumiendo siempre que lo de las arquitecturas poligonales y el diseño OO sea lo tuyo). Tenemos código claro, con nombres bien escogidos, responsabilidades aisladas, estamos escribiendo código idiomático al lenguaje y arquitectura elegidos, aplicamos patrones de diseño ampliamente conocidos y contrastados…

Todo lo que nos falta

Si la programación que hemos realizado en el ejemplo anterior es tan buena (o al menos no es horrible), ¿podemos estar tranquilos? La verdad es que no. Puede que el código cumpla todo eso que hemos mencionado antes, pero la implementación que hemos hecho de la funcionalidad presenta un montón de problemas que no están relacionados, al menos directamente, con el código que hemos escrito.

Pensemos un poco en lo que implica poder editar el contenido de un tweet.

¿Qué va a ocurrir con las respuestas a ese tweet? Es decir, ¿qué ocurre si escribo un tweet diciendo “El Real Madrid es el mejor”, alguien me contesta, “Qué razón tienes”, y luego lo edito y pongo “El Real Madrid es el peor”. ¿Se deben mantener las respuestas? ¿Se debe notificar a quien ha respondido para que pueda editar su respuesta? ¿Hace falta que los usuarios puedan saber si un tweet se editó y en qué momento?

Algo similar ocurre con los retweets. ¿Al cambiar el contenido del tweet se deshacen los retweets anteriores? ¿Se notifica a los usuarios para que elijan qué hacer con su retweet? ¿Y con los tweets que citan al original? Con los likes pasa algo parecido. Y con los momentos que enlazan al tweet.

Además, twitter es una aplicación distribuida con clientes parcialmente conectados. ¿En las aplicaciones móviles vamos a actualizar los tweets que están en el timeline para que vean el nuevo contenido? ¿Los dejamos desactualizados a menos que refresquen? Y eso en los clientes oficiales, ¿que hacemos con los demás clientes? ¿Exponemos un nuevo API para que puedan detectar los cambios?

Claro que también tenemos que pensar en los usuarios. ¿Van a entender la funcionalidad? ¿De qué manera se la vamos a exponer? ¿La vamos a desplegar a todos a la vez? ¿Probamos primero con algún grupo de usuarios? Y ya que hablamos de desplegar, ¿cómo haremos el paso a producción? ¿Hace falta modificar los datos existentes, por ejemplo para añadir una fecha de actualización? Si es así, ¿qué reglas vamos a seguir para actualizarlos?

Y todavía no hemos dicho nada de pruebas, porque ahora que hemos empezado a ver todas las implicaciones que tiene esto de editar un tweet, habrá que preparar una buena batería de pruebas (idealmente automatizada, pero al menos manual) para comprobar que todos estos casos que estamos encontrando funcionan como deben.

Cuando empezamos a analizar el problema nos damos cuenta de que el código que hemos escrito antes, por muy bonito, sólido y limpio que sea, no vale de mucho.

Desarrollar software

Creo que con este ejemplo podemos empezar a intuir a qué me refiero con que programar no es desarrollar.

En cuanto saltamos del divertido mundo de las katas y los puzzles al Mundo Real™, la parte de programación “pura” empieza a perder peso. Programar es una parte necesaria para desarrollar software, pero no es suficiente y tampoco es la más importante.

Seamos realistas, en las aplicaciones de línea de negocio que desarrollamos la mayoría de nosotros, gran parte de las funcionalidades no son nada complicadas de implementar y se basan en guardar algo en una base de datos, pintarlo en la pantalla adecuada, y hacer un par de cálculos por el camino.

Lo complicado suele venir de cómo interactúan esas funcionalidades con todas las demás que ya existen en el sistema, con cómo vamos a cambiar la forma de trabajar de los usuarios actuales, con cómo vamos a adaptar los datos ya existentes para que sean compatibles con las nuevas funcionalidades o de qué forma podrá venderse la funcionalidad de forma atractiva y eficiente.

En definitiva, la parte complicada es pensar, analizar y diseñar la solución desde el punto de vista de procesos y operativa, no de código.

Visto así, resulta tentador volver a pensar en jerarquías rígidas en las que unos señores muy listos hacen la labor de análisis funcional, transmiten ese análisis a arquitectos y diseñadores, los cuales pasan unos diagramas UML a programadores y listo. A pintar y colorear. Sin embargo no creo que eso funcione realmente.

Es cierto que es imposible que alguien sea bueno en todo, por lo que pretender que una persona sea a la vez experto en negocio, en experiencia de usuario, en usabilidad, en bases de datos, en despliegues en la nube y en otras mil cosas no tiene sentido. Pero hay alternativas.

Siempre se pueden construir equipos en los que quienes dominan estas áreas colaboren estrechamente para el desarrollo de cada funcionalidad, pero incluso si no existe esa disponibilidad de expertos, lo que sí esperaría de un desarrollador de software es que sea consciente de que es necesario preocuparse por esas cosas. Las hará mejor o peor, podrá necesitar más o menos ayuda externa para las áreas en las que más pueda cojear, pero al menos lo intentará.

En mi caso, trabajo en un equipo pequeño. Eso hace que a la hora de buscar compañeros le demos mucha importancia a esa capacidad de resolver problemas y tener una visión más amplia que escribir un código bonito. Sencillamente porque no nos podemos permitir tener una separación de roles en las que alguien analiza un problema, se lo pasa a otra persona para que diseñe el UX, y luego dan unas pantallas a un programador para que las implemente. Por supuesto le damos mucha importancia a la calidad del código, pero si no va acompañada de una preocupación por todo lo demás, no nos sirve de nada.

Por suerte, al igual que la mayoría del código que escribimos no tiene gran complejidad, muchas veces todas estas cosas que rodean al código tampoco son tan sumamente complejas vistas por separado como para necesitar grandísimos expertos en la materia. A lo mejor como desarrollador no eres experto, por ejemplo, en el negocio para el que estás desarrollando, o no tienes grandes dotes para el diseño de interacción, pero con que hagas pequeños avances en estas áreas, con que te preocupes un poco, el resultado mejorará enormemente.

Igual que ser capaz de escribir no te hace escritor, ser capaz de programar no te hace desarrollador. Hay mucho más que eso.

Posts relacionados:

  1. Desarrollar es sólo el principio
  2. Lo peor de desarrollar software
  3. No todo el mundo necesita programar (aunque es divertido)

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

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

Galardones de FileOptimizer

abril 08, 2018 10:43

¿Por qué use C++ Builder con FileOptimizer? desvelaba mi apuesta personal por Embarcadero C++ Builder desde hace más de 20 años. Volvemos a hacer balance de FileOptimizer, porque aunque la psicología evolutiva dice que quitamos importancia a los traumas sufridos en el pasado como simple condición de supervivencia, ello choca con un defecto que tenemos […]

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

La entrada Galardones de FileOptimizer aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

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

Blog Bitix

Introducción a NIO.2, el sistema de entrada/salida de Java

abril 07, 2018 12:00

Una de las tareas más importante que realizan algunas aplicaciones es el manejo de la entrada y salida ya sea al sistema de ficheros o a la red. Desde las versiones iniciales de Java se ha mejorado soporte añadiendo programación asíncrona de E/S, permitir obtener información de atributos propios del sistema de archivos, reconocimiento de enlaces simbólicos y facilitado de algunas operaciones básicas.

Java

En las primeras versiones de Java el sistema de entrada/salida proporcionado en el paquete java.io era básico. En la versión 1.4 de Java se añadió un nuevo sistema de entrada/salida llamado NIO para suplir algunas de sus deficiencias que posteriormente en Java 7 se mejoró aún más con NIO.2. Entre las mejoras se incluyen permitir navegación de directorios sencillo, soporte para reconocer enlaces simbólicos, leer atributos de ficheros como permisos e información como última fecha de modificación, soporte de entrada/salida asíncrona y soporte para operaciones básicas sobre ficheros como copiar y mover ficheros.

Las clases principales de esta nueva API para el manejo de rutas, ficheros y operaciones de entrada/salida son las siguientes:

  • Path: es una abstracción sobre una ruta de un sistema de ficheros. No tiene porque existir en el sistema de ficheros pero si si cuando se hacen algunas operaciones como la lectura del fichero que representa. Puede usarse como reemplazo completo de java.io.File pero si fuera necesario con los métodos File.toPath() y Path.toFile() se ofrece compatibilidad entre ambas representaciones.
  • Files: es una clase de utilidad con operaciones básicas sobre ficheros.
  • FileSystems: otra clase de utilidad como punto de entrada para obtener referencias a sistemas de archivos.

Con la clase Path se pueden hacer operaciones sobre rutas como obtener la ruta absoluta de un Path relativo o el Path relativo de una ruta absoluta, de cuanto elementos se compone la ruta, obtener el Path padre o una parte de una ruta. Otros métodos interesantes son relativize(), normalize(), toAbsolutePath(), resolve(), startsWith() y endsWith().

Utilizando estas clases expondré algunos ejemplos siendo el primero recorrer el listado de archivos o también se podría hacer el listado de forma recursiva de un directorio e imprimir la información de cada archivo como nombre, si es un enlace simbólico, permisos propietario, fecha de última modificación y tamaño utilizando los siguiente métodos similar a lo que hace el comando ls de GNU/Linux:

Al igual que es posible leer los permisos también es posible establecerlos con el método Files.setPosixFilePermissions().

Las operaciones de crear directorios o archivos, copiar archivos, moverlos y eliminarlos son muy comunes de modo que la clase Files ofrece varios métodos que con una única línea permite hacer estas operaciones de forma sencilla. El siguiente ejemplo crea un archivo, lo copia, lo mueve y finalmente lo elimina.

Para leer el contenido de archivos la clase Files ofrece los métodos newBufferedReader(), newBufferedWrite(), newInputStream() y newOutputStream() junto con otros como readAllLines() y readAllBytes().

En cuanto a la programación de entrada/salida asíncrona se ofrecen dos paradigmas uno basado en la clase Future y otro en funciones de rellamada o callbacks. La programación asíncrona evita bloquear el hilo que ejecuta el código y aprovecha mejor los procesadores multinúcleo con lo que se mejora el rendimiento de las aplicaciones. Para los ficheros se usa la clase AsynchronousFileChannel y para flujos de red AsynchronousSocketChannel.

Si se desea profundizar más en NIO y NIO.2 el libro The Well-Grounded Java Developer dedica un capítulo introductorio en el que me he basado para realizar este artículo, el libro Java I/O, NIO and NIO.2 está completamente dedicado al nuevo sistema de entrada/salida de Java y el tutorial Java Basic I/O también está muy bien como introducción.

En el artículo monitorizar archivos con Java muestro como recibir eventos cuando se añade, elimina o modifica algún archivo de los observados usando la clase WatchService.

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

Variable not found

Variable not found, por fin con HTTPS

abril 04, 2018 06:55

SeguridadPues creo que he tenido que ser el último de internet en hacer que su sitio web sea accesible con HTTPS, pero por fin puedo decir que la dirección https://www.variablenotfound.com ya está activa y, desde hace unos días, todas las peticiones hacia direcciones “http://…” del blog son redigiridas hacia su correspondiente versión segura “https://…”.

La verdad es que ha sido una espera larga, porque hasta hace bien poco la plataforma Blogger sólo ofrecía HTTPS a blogs que utilizaban el clásico subdominio “algo.blogspot.com”, pero no aquellos que usábamos dominios personalizados.

Esta necesidad era bastante frecuente y existían muchos foros, issues y consultas solicitando a Google (propietario de Blogger) que implementara esta funcionalidad, pero tras ver que esto llevaba varios años encallado y no avanzaba, hace no demasiado tiempo comencé a hacer algunas pruebas con Cloudflare, un servicio del que, por cierto, quedé gratamente impresionado. La idea era configurar este proveedor de servicios como proxy de variablenotfound.com haciendo que todas las peticiones pasasen por él, de forma que podría configurar ahí el certificado digital necesario para que las comunicaciones circulen con HTTPS. Todo esto se podía conseguir en Cloudflare de forma sencilla, en apenas unos minutos y de forma totalmente gratuita (incluido el certificado digital).

Sin embargo, al final no fue necesario porque poco después pude comprobar que Google por fin había cumplido su palabra, y ya desde el mismo panel de control los usuarios podemos activar el soporte HTTPS de forma bastante sencilla.

Configurando HTTPS en blogger

Al activar esta opción, Blogger genera automáticamente un certificado de Let’s encrypt y configura los servidores para que sea utilizado en los accesos al blog :)

Certificado de seguridad de Variable not found

Ya para poner un poco al día el blog creo sólo me falta hacerle una renovación completa de look, que a este se le notan ya bastante los años. Lo intenté el año pasado porque me hubiera gustado haber estrenado un nuevo traje para celebrar el décimo aniversario del blog, pero no fui capaz de conseguirlo. Creo que para dar a esto un buen lavado de cara hace falta mucho tiempo (os aseguro que tocar las plantillas de Blogger no es una tarea sencilla), así como grandes dosis de criterio y buen gusto, asuntos todos de los que no voy muy sobrado.

Bueno, todo se andará; vamos poquito a poco, pero siempre avanzando ;)

Publicado en Variable not found.

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

Variable not found

Enlaces interesantes 315

abril 03, 2018 06:55

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

.NET / .NET Core

ASP.NET / ASP.NET Core

Azure / Cloud

    Data

    HTML / CSS / Javascript

    Visual Studio / Complementos / Herramientas

    Otros

    Publicado en Variable not found.

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

    proyectos Ágiles

    Master en Agile – MMA 2018

    abril 02, 2018 09:57

    En octubre de 2018 se iniciará el Barcelona una nueva edición del Master en Métodos Ágiles (MMA) en La Salle (Universitat Ramon Llull). Tras 5 exitosas ediciones del formato anterior en forma de Postgrado y 2 de Máster, y dada la cantidad de conocimiento y áreas en las que se han ido extendiendo los principios ágiles, se ampliaron contenidos y profesorado para transformarlo en Máster, el primero a nivel mundial sobre Agile.

    MMA-banner

    Es una oportunidad única para aprender de profesionales de primer nivel, con varios años de experiencia específica en Agile, aplicando principios y métodos ágiles en contextos diversos, especializándose en aspectos concretos,  investigando sobre nuevas técnicas y ponentes en conferencias nacionales e incluso internacionales.

    Asignaturas Temas Profesores
    Fundamentos & Inception Principios y métodos más conocidos (Scrum, Lean, Kanban y XP). Facilitadores e impedimentos. Inception y conceptualización ágil de proyecto. Xavier Albaladejo
    Agustín Yagüe
    Scrum Estimación y planificación ágil, framework de Scrum, retrospectivas, métricas ágiles, herramientas ágiles físicas, radiadores de información. Tiago Garcez
    Silvia Sistaré
    Personas y equipos Gestión de personas, gestión de conflictos, motivación e incentivos, facilitación compartida, contratación ágil, coaching de equipos, liderazgo. Steven Wallace

    Manuel Lopez

    Joserra Díaz

    Ingeniería Ágil User eXperience y prototipado en Agile, ALM ágil, eXtreme Programing, Software Craftsmanship, arquitectura ágil, enterprise software development ágil, DevOps, testing ágil. Marc Pifarré

    Álvaro García

    Pablo Gómez

    TDD, BDD, Legacy code Desarrollo guiado por pruebas (de aceptación y unitarias), cómo trabajar con código heredado y reducir la deuda técnica. Carlos Ble
    Rubén Bernárdez
    Agustín Yagüe
    Enterprise Learning & personal efficiency Comunidades de Práctica, Open Spaces, Talent development, gamification, Productividad y aprendizaje personal en Agile. Steven Wallace
    Manuel Lopez
    Vanesa Tejada
    Kanban, Lean & continuous improvement Kanban, Lean Thinking, Lean Software Development, Mejora Continua en Agile Xavier Quesada

    Ángel Medinilla

    Cultura y Agile Management Tipos de cultura empresarial, gestión del cambio organizativo, Agile Management. Jasmina Nikolic
    Jaume Gurt
    Gabriel Prat
    Lean Startup y Enterprise Product Management Lean Startup, innovación, Design Thinking, Impact Mapping, lanzamiento de startups ágiles, Agile Product Management, Product Portfolio Management, Roadmapping, Budgeting for Agile Gabriel Prat
    Ángel Díaz-Maroto
    Mattijas Larsson
    Scaling Agile & Rollout Escalado (LESS, Spotify, Nexus, SAFe), desescalado y auto-organización empresarial (reinventing organizations, sociocracy, …), contratos ágiles. Adrian Perreau
    Fernando Palomo
    Xavier Albaladejo
    Trabajo Final de Máster Durante el Máster se elaborará un caso práctico de introducción y aplicación de Agile en una empresa, incluyendo la parte de transformación organizativa y de cultura

    Algunos comentarios de los alumnos en ediciones anteriores en forma de Postgrado: “Cuando se acaba la clase, estamos ya esperando a que llegue la semana que viene para ver un nuevo tema con el siguiente profesor”. “Muy práctico”. “La calidad y diversidad de puntos de vista entre los profesores le aporta mucho valor”.  Más detalles en: Mejora de la situación laboral los alumnos del PMA trans un año.

    Además de los conocimientos concretos que se reciben, uno de los principales cambios que han experimentado los alumnos es mayor perspectiva en los problemas, cómo abordar la complejidad en las empresas, en su trabajo y en las relaciones entre personas y en equipos. Han ganado discurso y aplomo para defender de manera más objetiva propuestas de cambio y mejora.

    El Máster tendrá una duración de un año académico y se realizará viernes tarde y sábado por la mañana.

    Para más detalles, consultar la página oficial del Máster.

    –> Ver también cuál ha sido la Mejora de la situación laboral de los alumnos tras un año y los Principales aspectos valorados por los alumnos.

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

    Poesía Binaria

    Cómo permitir solo la ejecución de una instancia de nuestros scripts

    abril 02, 2018 08:21

    Aunque me gusta que los programas sean flexibles y nos permitan una ejecución libre y sin restricciones. Además, quiero que permitan editar varios archivos a la vez y realizar múltiples conexiones. Hay software o scripts en los que debemos asegurar que sólo se haga una ejecución simultánea ante diferentes condiciones. Por ejemplo, si es un script para realizar copias de seguridad de nuestro sistema, tal vez nos interese que sólo se pueda lanzar una vez, porque sería un problema que se realicen dos copias de seguridad a la vez. Si recopilamos información de salud del sistema, podemos empeorar dicha salud si estamos recopilando varias veces esos datos, podríamos empeorar el rendimiento del sistema. O si estamos realizando una captura de pantalla a través de un script nuestro, puede ser contraproducente lanzar el mismo programa de forma simultánea varias veces.

    Así que, en principio, tenemos que tener claro a qué nivel queremos restringir la ejecución de las instancias de nuestro programa. Es decir, ¿sólo permitimos una ejecución en todo el sistema? ¿una por usuario? ¿una por usuario y directorio de trabajo? Nosotros debemos definir la restricción de acuerdo a nuestras necesidades.

    Una ejecución a nivel de sistema

    Como siempre, hay muchas formas de complicarnos la vida con estos scripts. Ya depende de lo grande que sea nuestro script y la precisión u opciones que necesitemos. Empezaremos con algo muy sencillo, utilizando el comando pidof para buscar el número de instancias con el mismo nombre que el programa actual. Si ejecutamos, por ejemplo:

    pidof -x firefox
    6249 6178 6068 5979

    Este comando nos devolverá los PIDs de los procesos que se llaman firefox. Y, por supuesto, podemos contar el número de comandos que hay (con wc -w). Del mismo modo podemos construir un script en bash que busque entre todos los programas en ejecución los que se llaman como él y decida detener la ejecución si hay más de uno:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #!/bin/bash

    MYPID=$$
    MYNAME=$0
    PROCS=$(pidof -o "$MYPID" -x "$(basename "$MYNAME")")
    echo "Inicio---"
    echo $PROCS | wc -w

    if [ "$(echo $PROCS | wc -w)" -gt 0 ]; then
         echo "Ya hay una instancia en ejecución. Saliendo"
         exit;
    fi

    echo "Hago una espera para simular que el script hace cosas, y que tarda un poco."
    echo "Nos dará algo de tiempo para iniciar más ejecuciones del mismo script"
    sleep 10
    echo "El script ha terminado"
    echo " ---------------- "

    En este caso nuestra ejecución de pidof es más compleja, podíamos hacer la misma petición de antes (sin -o “$MYPID”), pero me gusta cómo queda el código así. En este caso, le estamos diciendo a pidof que excluya de la lista de PIDs que nos devuelve la PID actual. Luego, en la sentencia condicional if miramos si este número es mayor que 0 (-gt 0). Si lo es, ya existe un proceso que se llama como el proceso actual (sacamos el nombre con $(basename $0), así cogemos el nombre del archivo que se ha ejecutado, lo podemos poner a mano, pero así es más genérico). En caso de no incluir -o “$MYPID” en la línea de pidof, deberíamos comparar con (-gt 1), ya que pidof en este caso siempre va a devolver al menos una PID, la del proceso actual.

    En este ejemplo vemos que se ha colocado primero el resultado de pidof en una variable. Podríamos hacer la sentencia de golpe (pidof … | wc …), pero algunos intérpretes como Bash, internamente cuando encuentran el pipe (|), hacen un fork del proceso actual, es como si lo duplicaran, de forma que justo en el momento en el que estamos mirando los procesos, hay un proceso más con el mismo nombre. Podríamos, por ejemplo, añadir un número más en la comparación (-gt 1 en lugar de -gt 0; o -gt 2 en lugar de -gt 1), pero al ser un tema de comportamiento interno del intérprete, puede que no funcione bien en futuras versiones o en otros intérpretes.

    El principal problema que encontramos en este enfoque es que buscamos procesos por su nombre. Y cualquiera podría crear un proceso con el mismo nombre, tenerlo en ejecución siempre y evitaría que pudiéramos ejecutar el programa (intencionadamente o sin querer). Por otro lado, esto sería a nivel de sistema, es decir, no podríamos establecer restricciones tipo una instancia por usuario. También es lento, bueno, aunque el script se ejecuta muy rápido, no es eficiente. Para obtener las PID de los procesos que se llaman igual, pidof, internamente mira todas las PID de todos los procesos y hace una comparación con una cadena de caracteres, lo que pueden ser varios millones de operaciones. Además, esto puede traernos problemas, ya que la ejecución de pidof tarda un tiempo y si el programa se ejecuta dos veces muy seguidas una de otra, pueden pasar tres cosas (y no podemos controlar el resultado):

    • Que todo vaya bien y funcione perfectamente. Es el caso ideal, pero un fallo es probable.
    • Que los dos procesos detecten al otro proceso y ninguno de los dos se inicie.
    • Que ningún proceso detecte otro proceso y se inicie dos veces.

    De todas formas, este es un buen método, y muy rápido de programar, sin complicarnos la vida.

    Directorio o fichero de bloqueo

    Otra opción es crear un directorio o fichero de bloqueo. Por un lado, es más rápido crear directorios, aunque en los ficheros podemos escribir dentro (vale, dentro de los directorios también podemos escribir, pero tendremos que crear archivos y para leer un valor debemos primero comprobar que un fichero existe y nos eternizaríamos demasiado). Esta primera aproximación la haremos utilizando comandos básicos, y la usaremos cuando no podamos utilizar flock (la siguiente opción), ya sea por tratarse de un sistema empotrado con versiones reducidas del sistema, o tengamos alguna incompatibilidad.
    Esta aproximación nos permitirá:

    • Establecer varios tipos de bloqueo: a nivel de sistema, usuario o con el criterio que queramos, cambiando el nombre del directorio.
    • La probabilidad de tener problemas de condición de carrera como antes es menor, pero existe.
    • El bloqueo depende del fichero o directorio y no del nombre de proceso. Por lo que varios procesos pueden utilizar el mismo bloqueo.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #!/bin/bash

    LOCKDIR="/tmp/myprocess_"$(whoami)

    if [ -d "$LOCKDIR" ]; then
         echo "Ya hay una instancia en ejecución. Saliendo"
         exit;
    fi
    trap "rmdir $LOCKDIR" EXIT
    mkdir "$LOCKDIR"

    echo "Creando un proceso que hace muchas operaciones durante un tiempo"
    sleep 10
    echo "El script ha terminado"
    echo " ---------------- "

    En este ejemplo, lo primero que hacemos es crear un nombre de directorio de bloqueo ($LOCKDIR). Si éste existe, no dejamos pasar y cerramos el programa. Si no existe, creamos el directorio y hacemos que a la salida se borre (con trap … EXIT capturamos la salida del programa y ejecutamos un comando). Lo malo es que si matamos el proceso (nosotros o el sistema operativo debido a un fallo), nos vemos obligados a borrar manualmente el directorio /tmp/myprocess_USUARIO para poder volver a ejecutar el programa.

    File locks

    Llegamos hasta un comando con mucha potencia a nivel de sistema operativo. Con este programa podemos gestionar la ejecución de órdenes a partir de un bloqueo hecho sobre un fichero o directorio que gestionará si podemos o no podemos ejecutar el programa. (Atómico?)

    Lo más sencillo es probarlo en dos terminales. Aquí comprobaremos los diversos modos de trabajo:

    flock /tmp/bloqueo -c “echo INICIO; sleep 10; echo FIN”

    Con esto, estableceremos un bloqueo sobre /tmp/bloqueo (un nombre de archivo que acabamos de inventarnos) y hacemos que cuando esté desbloqueado, escribamos en pantalla “INICIO”, luego esperemos 10 segundos y finalmente escribamos “FIN” en pantalla. Algo muy sencillo, pero en el mundo real, en lugar de una espera de 10 segundos, podremos ejecutar una tarea que sea peligrosa, y no pueda ser hecha por varios procesos a la vez. Pensemos en la lectura/escritura de ficheros o dispositivos, acceso por red a un determinado recurso, etc; o, como es nuestro caso, a la ejecución de un script que no puede ser ejecutado dos veces simultáneas.

    El experimento que quiero llevar a cabo es el siguiente. Mientras transcurren los 10 segundos de espera del script anterior, debemos ejecutar, entro terminal lo siguiente:

    flock /tmp/bloqueo -c “echo \”HOLA MUNDO\””

    De forma que, cuando el recurso /tmp/bloqueo no esté bloqueado, se escriba en pantalla HOLA MUNDO. De esta forma veremos que HOLA MUNDO no se escribirá inmediatamente, sino cuando concluya la espera de 10 segundos del otro terminal. Hemos establecido, una forma de comunicación entre dos procesos diferentes, en forma de bloqueo. Aunque, como vemos ahora, el segundo proceso esperará de forma indefinida a que el primero termine. Y, el primero puede no terminar nunca. ¿Por qué? Bien porque se haya quedado el proceso colgado, o porque hayamos matado de mala manera el proceso, o simplemente el proceso está tardando mucho y debemos cancelar la espera y ponernos a otra cosa. Cosas que pasan en el mundo real. Esto lo podemos hacer de la siguiente manera:

    flock -w 3 /tmp/bloqueo -c “echo \”HOLA MUNDO\””

    De esta forma, flock esperará durante 3 segundos (también podemos poner fracciones de segundo) antes de darse por vencido y no ejecutar nada. Es decir, si antes de 3 segundos, el recurso se libera, escribiremos HOLA MUNDO; si no, no haremos nada, simplemente saldremos. Además, devolveremos un código de salida, por defecto, el código será 0 si se ha podido coger el recurso y ejecutar la orden (el hola mundo), de lo contrario, devolverá 1. Aunque este valor lo podemos personalizar con -E valor. Para ver el código de salida podemos hacer:

    flock -w 3 /tmp/bloqueo -c “echo \”HOLA MUNDO\””
    echo $?
    1

    Ahora, integremos flock en nuestro script. De manera que podamos ejecutar un proceso por usuario del sistema:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #!/bin/bash

    LOCKFILE="/tmp/myprocess_"$(whoami)
    MYPID=$$

    function exit_error() {
        echo "Ya hay una instancia en ejecución. Saliendo"
        exit 1
    }

    (
        flock -n 3 || exit_error
        echo "Creando un proceso que hace muchas operaciones durante un tiempo"
        sleep 10
        echo "El script ha terminado"
        echo " ---------------- "
    ) 3> "$LOCKFILE"

    Con el uso de flock no tenemos que preocuparnos por los posibles problemas de desbloqueo ni condiciones de carrera. Es decir, el sistema operativo se encargará de gestionar los recursos bloqueados, en este caso, nuestro fichero de bloqueo (/tmp/myprocess_USUARIO). Si por algún casual el proceso muere, el núcleo del sistema operativo se encargará de eliminar el bloqueo para que otro proceso ocupe su lugar, lo mismo pasa cuando el proceso termina. Además, si dos procesos llaman a flock a la vez, sólo uno obtendrá el bloqueo exclusivo.

    En este caso, en lugar de vincular el bloqueo a un archivo directamente, lo hemos vinculado a un descriptor (un descriptor no es más que un número con el que nos referimos al recurso que queremos utilizar, porque para un ordenador es mucho más fácil manejar números). Y dicho descriptor (el 3, porque yo lo valgo, pero que puede ser un número mayor a 2 porque 0, 1 y 2 están pillados; aunque podemos poner el 100 por ejemplo) lo relacionamos con el archivo en cuestión.

    Aunque esta sintaxis puede ser un poco liosa y confusa. A mí me gusta más llamar a una función de bloqueo (y quitarme del medio los paréntesis, y el número 3 escrito en varias partes del programa, porque me gustaría más ponerlo en forma de variable pero en la última línea no podremos ponerlo). Así que, vamos a modificar un poco el código:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #!/bin/bash

    LOCKFILE="/tmp/myprocess_"$(whoami)
    LOCKFD=150
    MYPID=$$

    function lock() {
        echo {LOCKFD}>$LOCKFILE
        flock -n $LOCKFD
    }

    function exit_error() {
        echo "Ya hay una instancia en ejecución. Saliendo"
        exit 1
    }

    lock || exit_error

    echo "Creando un proceso que hace muchas operaciones durante un tiempo"
    sleep 10
    echo "El script ha terminado"
    echo " ---------------- "

    La clave aquí está en que la función lock crea el archivo vinculado al descriptor $LOCKFD (¡lo he sacado a una variable aparte!), aunque la forma de hacerlo aquí con echo {LOCKFD}>$LOCKFILE requiere Bash 4.1. Si lo queremos hacer con versiones anteriores debemos recurrir a eval (que personalmente, prefiero evitar). Luego hacemos el flock en el que nos aseguramos de devolver 0 si todo va bien y 1 si algo va mal. De esta forma, la función lock se basta y se sobra para establecer el bloqueo y en el resto del código no nos tenemos que preocupar de nada más.

    Detección de scripts sobas

    Algo que puede pasar mientras ejecutamos los scripts es que uno tarde demasiado en finalizar. Por ejemplo, lanzamos un script de copia de seguridad, que lo mismo puede estar 4 o 5 horas en ejecución si tenemos muchos datos, o si estamos comprimiendo o codificando nuestras backups. Así que, vamos a incluir en nuestro script un pequeño aviso del tiempo que lleva el otro proceso ejecutándose.

    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
    #!/bin/bash

    readonly LOCKFILE="/tmp/myprocess_"$(whoami)
    LOCKFD=150
    readonly MYPID="$$"
    readonly MYNAME="$(basename "$0")"

    function lock() {
        local PID="$(cat $LOCKFILE)"
        echo {LOCKFD}<>$LOCKFILE

        flock -n $LOCKFD
        local STATUS=$?

        if [ $STATUS = 0 ]; then
            # Escribimos nuestra PID
            echo $MYPID >&${LOCKFD}
            return 0
        else
            local PROCNAME="$(cat /proc/$PID/comm 2>/dev/null)"
            if [ "$PROCNAME" != "$MYNAME" ]; then
                echo "Error, el proceso ejecutado no coincide con el que debe"
                exit 1
            fi
            local FROMTIME=$(awk -v ticks="$(getconf CLK_TCK)" -v epoch="$(date  %s)" '
                NR==1 { now=$1; next }
                END { printf "%9.0f", epoch - (now-($20/ticks)) }'
    /proc/uptime RS=')' /proc/$PID/stat | xargs -i date  "%d/%m/%Y %H:%M:%S" -d @{})
            echo "El proceso $PID ($PROCNAME) lleva abierto desde $FROMTIME"
            return 1
        fi
    }

    function exit_error() {
        echo "Ya hay una instancia en ejecución. Saliendo"
        exit 1
    }

    lock || exit_error

    echo "Creando un proceso que hace muchas operaciones durante un tiempo"
    sleep 10
    echo "El script ha terminado"
    echo " ---------------- "

    En este caso, escribimos la PID del proceso que bloquea el recurso en el mismo fichero de recurso (podríamos utilizar otro, pero bueno). Entonces, cuando falla el establecimiento del bloqueo, buscamos el nombre del proceso con la PID que hay escrita y a partir de ahí averiguamos cuándo se inició el mismo (tenemos que mirar en stat y analizar el resultado, por eso el script de awk). Luego, presentamos en pantalla cuándo se inició dicho proceso.

    Conclusión

    Dependiendo de nuestro script podremos utilizar una u otra solución o, incluso otra totalmente diferente. Aunque es importante asegurarse que cuando nuestro script esté utilizando recursos o elementos que no deban ser utilizados simultáneamente, hagamos un bloqueo antes de causar un desastre. Imaginad por ejemplo que inicio dos veces una copia de seguridad diaria de base de datos que escribe sobre el mismo fichero o que empiezo el envío de un mailing dos veces, antes de que se marque como enviado. Esto puede dar lugar a errores en copias de seguridad o envíos de correo no deseado, o correos duplicados que, pueden causar que muchos usuarios se den de baja de nuestra lista de distribución.

    ¿Qué método prefieres para bloquear tu script?

    Foto principal: unsplash-logoMILKOVÍ

    The post Cómo permitir solo la ejecución de una instancia de nuestros scripts appeared first on Poesía Binaria.

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

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

    ¿Por qué C++ Builder?

    abril 02, 2018 07:40

    Empecé usando C++ Builder en 1996 con la versión 1.0, muchos lo conocíamos todavía como Ebony, el nombre en clave del producto. Desde entonces, he sido un apasionado de este entorno de desarrollo, en realidad ya lo era antes con Turbo C, lo que no dejan de ser un argumento más en favor de mi […]

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

    La entrada ¿Por qué C++ Builder? aparece primero en Bitácora de Javier Gutiérrez Chamorro (Guti).

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

    Picando Código

    20 años de Mozilla

    marzo 31, 2018 08:25

    Hoy se cumplen 20 años del nacimiento del proyecto Mozilla. Los que leen el blog seguido sabrán que soy un gran admirador y seguidor de la fundación. Desde este humilde espacio en la web he ido escribiendo sobre varios proyectos, noticias y experimentos de Mozilla a lo largo del tiempo. Así que hoy dedico esta nota a difundir lo que se viene informando en el blog oficial de Mozilla.

    Como parte de la celebración, se publicó la primera adición a los principios que forman el fundamento del trabajo de Mozilla. Estos principios están establecidos en el Manifiesto Mozilla, el cual fue lanzado en 2007. El Manifiesto Mozilla identifica diez principios por los que se trabaja para construir en Firefox y la vida en línea en general.

    Internet debería ser un recurso público global, abierto y accesible a todos. Los individuos deberían tener control de su experiencia. La seguridad es crítica. El lucro comercial privado y el beneficio social deberían coexistir de manera saludable. Estos principios se usan regularmente para describir la identidad de Mozilla y para informar su toma de decisiones. El Manifiesto puede ser leído en este enlace.

    En este aniversario se agregan cuatro temas al Manifiesto Mozilla. Esto se hace para para abordar explícitamente la calidad de la experiencia de las personas en línea.

    • Estamos comprometidos a una internet que incluye a todas las personas de la Tierra – donde las características demográficas de una persona no determinan su acceso en línea, oportunidades o calidad de la experiencia
    • Estamos comprometidos a una internet que promueve discurso cívico, dignidad humana, y expresión individual.
    • Estamos comprometidos a una internet que eleva el pensamiento crítico, argumento razonado, conocimiento compartido y hechos verificables.
    • Estamos comprometidos a una internet que catalice la colaboración entre diversas comunidades trabajando en conjunto con una meta común.

    Es increíble que en 2018 el pensamiento crítico tenga que ser explicitado, pero lamentablemente necesario. De hecho considero los cuatro principios como sentido común. Pero obviamente tanto las empresas como individuos con poder e intereses egoístas e ignorantes no necesitan respetarlos para alcanzar sus objetivos. Creo que todos, como desarrolladores y partícipes de Internet así como en nuestra vida diara, deberíamos tener presentes estos principios.

    Mozilla se compromete a usar el manifiesto como guía para su trabajo, diseñando productos, construyendo tecnología y comunidad y trabajando con otros. Desde su lugar también esperan animar, crear, liderar y apoyar muchos experimentos que intenter traer a la vida estas metas, y esperan unirse con otros persiguiendo ideas similares. Por esto y más apoyo a Mozilla como fundación, y acepto sus aciertos y errores como grupo humano que son, mientras continúen respetando su manifiesto, evolucionando, creciendo y cambiándolo cuando es necesario.

    En otro artículo del blog de Mozilla, Mitchell Baker (presidenta de la fundación) escribe:

    Mozilla no fue originalmente destinado a crear productos de consumo. Se esperaba que fuera una organización de desarrollo de tecnología que haría tecnología disponible para Netscape y otros que construirían productos de consumo. Con el tiempo encontramos que a la gente le gustaba la versión de desarrollo que Mozilla venía entregando y empezamos a movernos hacia producir productos en vez de tecnología.

    ¡Hemos recorrido un largo camino desde entonces!

    En mis sueños más locos no podría haber imaginado cuánta gente se sentiría atraída a la misión de Mozilla y eligiría afiliarse con Mozilla de alguna forma. Esto incluye a empleados, contribuidores voluntarios, “amigos de Mozilla” y un rango de gente incluso más amplio que reconoce lo que Mozilla representa y quiere más de esto en este mundo. Para mí, esto es el legado más rico. Hay mucho por hacer siguiendo adelante para constuir una internet más saludable que tenga experiencias humanas mejores.

    No hay un mapa detallado – lo construiremos juntos. Seguiremos adelante, hacia los costados, y en círculos. Es una aventura, y probablemente no para los débiles de corazón. Pero para esos que aman la aventura, prosperan en el cambio, y quieren ser recordados por construir valores decentes en grandes productos y programas – para nosotros, no hay mejor lugar en el que estar.

    Gracias Mozilla por seguir luchando por los derechos de los usuarios en Internet, y hacer que Internet sea un lugar mejor.

    Si quieren saber más del primer año de Mozilla, les recomiendo ver el documental Code Rush, que muestra la historia del lanzamiento del código fuente de Netscape como código abierto:

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

    Picando Código

    La historia del Proyecto Mozilla

    marzo 31, 2018 12:18

    Mozilla Logo

    El proyecto Mozilla fue creado en 1998 con la liberación del código fuente del navegador web Netscape. Estaba destinado a aprovechar el poder creativo de miles de programadores en Internet y alimentar niveles sin precedentes de innovación en el mercado de navegadores. Durante el primer año, miembros nuevos de la comunidad global ya habían contribuido nueva funcionalidad, mejorado características existentes y se habían comprometido en la gestión y planificación del proyecto en sí.

    Creando una comunida abierta, el proyecto Mozilla se había vuelto más grande que cualquier empresa. Miembros de la comunidad se involucraron y expandieron el alcance de la misión original del proyecto – en vez de sólo trabajar en el próximo navegador de Netscape, la gente comenzó a crear una variedad de navegadores, herramientas de desarrollo y una gama de distintos proyectos. La gente contribuía a Mozilla de maneras diferentes, pero todos estaban apasionados por crear software libre que permitiera a la gente tener una elección en cómo experimentaban Internet.

    Tras varios años de desarrollo, Mozilla 1.0, la primera versión mayor, fue lanzada en 2002. Esta versión contenía muchas mejoras al navegador, cliente de correo y otras aplicaciones incluidas en el suite, pero no mucha gente la estaba usando. En 2002, más del 90% de los usuarios de Internet navegaban con Internet Explorer. No mucha gente lo notó en el momento, pero la primera versión de Phoenix (más tarde renombrado a Firefox) también fue lanzada por miembros de la comunida Mozilla ese año con la meta de proveer la mejor experiencia de navegación posible a la más amplia cantidad posible de personas.

    En 2003, el proyecto Mozilla creó la Fundación Mozilla, una organización independiente sin fines de lucro apoyada por donantes individuales y una variedad de empresas. La nueva Fundación Mozilla continuó el rol de gestionar las operaciones diarias del proyecto y también asumió oficialmente el rol de promover apertura, innovación y oportunidad en Internet. Lo hizo continuando con lanzar software, como Firefox y Thunderbird, y expandiendo a nuevas áreas, como proporcionando subvenciones para apoyar mejoras de accesibilidad en la Web.

    Firefox 1.0 fue lanzado en 2004 y se transformó en un gran éxito – en menos de un año, fue descargado más de 100 millones de veces. Nuevas versiones de Firefox han venido saliendo regularmente desde entonces y siguen rompiendo nuevos récords. La popularidad de Firefox ha ayudado a devolver la elección a los usuarios. La competencia renovada ha acelerado la innovación y mejorado Internet para todos.

    En 2013, lanzaron Firefox OS para liberar toda la potencia de la Web en teléfonos móviles y una vez más ofrecer control y elección a nuevas generaciones de personas entrando en línea.

    Mozilla también celebró su decimoquinto aniversario en 2013. La comunidad ha mostrado que las empresas comerciales se pueden beneficiar colaborando en proyectos de código abierto y que grandes productos orientados al usuario final pueden producirse como software de código abierto. Más gente que nunca antes está usando Internet y están experimentándola en su propio idioma. Se ha creado una organización sustentable que usa mecanismos de mercado para apoyar una misión de beneficio público y este modelo ha sido reusado por otros para crear organizaciones abiertas, transparentes y colaborativas en una amplia gama de áreas.

    El futuro está lleno de desafíos y oportunidades iguales a las de nuestro pasado. No hay garantía que Internet se vaya a mantener abierta o disfrutable o segura. Mozilla continuará proveyendo una oportuindad para que las voces de la gente sean escuchadas y puedan moldear sus vidas en línea. Por supuesto, no estamos solos haciendo esto. La comunidad Mozilla, junto a otros proyectos de código abierto y otras organizaciones de beneficio público, existen sólo por las personas que están comprometidas en hacer nuestras metas comunes una realidad. Si quieres unirte a la misión, involúcrate.

    Para más información sobre la historia de Mozilla, ver lo siguiente:

    Traducción de: History of the Mozilla Project

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

    Blog Bitix

    Qué es y cómo funciona el type erasure en Java

    marzo 31, 2018 08:30

    Los tipos genéricos en Java se implementaron usando type erasure por simplicidad en la implementación, no incurrir en penalizaciones de rendimiento o memoria y por mantener la compatibilidad con versiones anteriores de Java. Son varios los conceptos que están asociados a la implementación de los tipos genéricos en Java que es recomendable conocer como type erasure y métodos bridge de este artículo pero también heap pollution, non-reifiable, wildcards y bound type parameters.

    Java

    En la introducción de los tipos genéricos en Java con la versión 1.5 se decidió implementarlo usando type erasuse que consiste en que en tiempo de ejecución se pierde la información de los tipos genéricos y para la máquina virtual no son distintos de un tipo no genérico, es un proceso que realiza el compilador. Esto tiene sus ventajas y algunas desventajas pero hay dos buenos motivos por los que en Java se decidió implementar los tipos genéricos usando type erasuse.

    Un motivo es que los tipos al ser en tiempo de ejecución exactamente iguales que los no genéricos de versiones anteriores se mantiene la compatibilidad hacia atrás tanto a nivel de código como a nivel binario lo que significa en un caso que el código fuente no es necesario que sea modificado y en otro que no es necesario recompilarlo y esto es importante para usar nuevas versiones de Java sin ningún tipo de modificación y para que programas antiguos sigan funcionando. El segundo motivo es que el mismo tipo sirve para todas las posibles instancias del tipo genérico, de forma que es eficiente y no se incurre en ninguna penalización de rendimiento o memoria.

    La desventaja del type erasure es que en tiempo de ejecución no se pueden hacer algunas optimizaciones, en computación y uso de memoria. Sin embargo, evaluando las ventajas y desventajas los desarrolladores de Java siempre han dado gran importancia en la compatibilidad hacia atrás y por ello prefirieron implementar los generics usando type erasure.

    El proceso de eliminar los tipos de los genéricos se realiza eliminando todos los parámetros de los tipos parametrizados siendo reemplazados con su restricción (bound), con el tipo Object o con con su restricción, si tiene múltiples restricciones se usa la primera.

    En Java dos métodos distintos no pueden tener la misma firma, dado que los generics han sido implementados con type erasure también se ha de cumplir que dos métodos no pueden tener la misma firma una vez aplicado el erasure. Para no perder las validaciones de tipos el compilador inserta los cast necesarios. El código fuente de una clase genérica sería el siguiente, que el compilador transformaría siguiendo las reglas del type erasure.

    Al mismo tiempo que el compilador inserta los cast necesarios para mantener la validación de tipos inserta métodos bridge para mantener el polimorfismo en las clases que extienden de tipos genéricos. Si se extiende la clase Node anterior y se aplica type erasure la firma del método setData de IntegerNode no coincide con el de la clase Node. Para solventar este problema el compilador inserta un método bridge para el método setData con un parámetro Object que se encarga de hacer de puente y llamar al método setData que recibe un Integer aplicando un cast.

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

    Picando Código

    Ciberpolítica – la privacidad en la era digital: desafíos y perspectivas

    marzo 28, 2018 09:49

    Hoy salió un especial en la diaria en conjunto con DATYSOC sobre ciberpolítica en el que tuve el gusto de participar. Un gran trabajo de Fabrizio Scrollini en coordinar a varios colegas para escribir distintos artículos sobre temas de privacidad, vigilancia y ética. El especial salió como parte de la diaria el día de hoy:

    Ciberpolítica: Cuestiones éticas

    Las notas:

    Una vigilancia sin precedentes – Dr. Fabrizio Scrollini, investigador a cargo de Datysoc.

    El análisis de datos y la mirada humana –  Lorena Etcheverry, profesora adjunta del Instituto de Computación, Facultad de Ingeniería, Udelar

    Privacidad y protección de datos en la tecnología educativa – Soc. Mariana Fossatti, investigadora, Datysoc y Dra. Patricia Diaz, investigadora, Datysoc.

    La ética hacker – Fernando Briano, desarrollador y hacker cívico.

    ¿Por qué la mayoría de los usuarios de internet usamos contraseñas tan inseguras? – Dr. Matias Dodel, investigador, Universidad Católica del Uruguay

    Los desafíos de la privacidad en la era digital – Dra. Ana Tuduri, investigadora, Datysoc.

    Inteligencia artificial y grandes datos: algunos apuntes – Dr. Tomas Laurenzo, profesor asociado, Universidad de la Ciudad de Hong Kong.

    Algunos piques – Ing. Mateo Martinez, cofundador de Charrua.

    ¿Qué es ser un delincuente en la era digital? – Dr. Fabrizio Scrollini, investigador a cargo de Datysoc

    Es la primera vez que escribo para un medio como la diaria, y fue algo surreal leer mi nombre en la publicación. Pero con suerte no será la última. Los invito a leer las notas y si les interesa saber más estén atentos a Datysoc y la diaria:

     

    » 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

    Sponsors

    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