Porqué creo que es útil discutir de Tabuladores y Espacios

Posted: agosto 15th, 2017 | Author: | Filed under: Sin categoría | Tags: , , , , | No Comments »

Discutir de tabuladores y espacios es importante útil.

Por mucho scrum y mucha retro, generar el clima de confianza adecuado para cagarse en el facilitador o que los nóveles opinen si se debe usar una arquitectura hexagonal es difícil. Discutir sobre el color del cobertizo para bicicletas, en algunos contextos será una perdida de tiempo y energía. En otros será una buena actividad, un ejercicio práctico antes de elevar el nivel de abstracción de las discusiones.

Y en todo caso, es algo que hay que decidir, así que mejor que sea por consenso.


Charlas “Programming Style” por Douglas Crockford

Posted: julio 1st, 2017 | Author: | Filed under: Sin categoría | Tags: , , , , , , | No Comments »

Otra de las series de charlas más conocidas de Crockford, son en las que habla de la importancia del estilo de código que empleamos.

A good style can help produce better programs. Style should not be about personal preferences and self-expression. Douglas Crockford

De esta serie creo que la más interesante es:

  • YUIConf 2011. 66′. Douglas Crockford. Programming Style & Your brain. En esta charla Crockford explica lo importante que es usar un estilo de código adecuado, y como hay estilos mejores que otros (según el lenguaje que estemos usando). Al programar no debemos tratar de demostrar lo listos que somos, si no escribir código para que otros puedan entenderlo, y hay estilos que favorecen esto además de reducir los bugs que podamos cometer. La charla se centra en Javascript y la herramienta JSLint, pero el porqué de usar un estilo y herramientas es importante vale para cualquier lenguaje.

Otras charlas similares serían:

Escogiendo un estilo de código

Crockford dice que al escoger un estilo, debemos priorizar (y en ese orden) que:

  1. Evite errores (aunque sea errores que raramente sucedan)
  2. Sea legible. Comuniqué claramente su intención al resto de programadores. Y se debe preferir esto sobre ahorrar memoria o velocidad.

Algunos comentarios de estilo de su charla con los que estoy de acuerdo

La llave va a la derecha

La llave va a la derecha, porqué el siguiente código en js produce un error silencioso:

1
2
3
4
return
{
ok: false
};

Mientras que esto funciona correctamente:

1
2
3
return {
ok: false
};

Usar Strict Equality Comparison

No usar nunca “==” usar siempre “===”. Evita resultados indeseados al hacer casting.

No usar el slash para generar strings multilínea

No usar el slash para generar strings multilínea porqué si hay un espacio después del slash se produce un error

1
2
"hola \
mundo"

Usar siempre las llaves para los bloques de código

Usar siempre las llaves aunque sea para escribir en la misma linea if (flag) { doSomething(); }

No usar pre/post incremento

No usar pre/post incremento. En lugar de ++x o x++ usar x+=1; Los primeros casos obligan a pensar más en lo que se está haciendo de que valor va a tener x cuando se ejecute algo, e introduce más errores.

No usar asignación transitiva

No usar la asignación transitiva var a = b = 0. Porqué no está claro si lo que se quería hacer era

1
2
3
4
5
var a = 0,
b = 0;

b = 0;
var a = b;

En los switch usar siempre break

En el switch usar siempre break después de cada caso. Es muy fácil usarlo mal, y que se presente un bug difícil de depurar.

Forma de usar las IIFE

Al usar Immediately Invocable Function Expression, preferir la tercera forma que aparece aquí

1
2
3
4
5
6
7
8
9
10
11
function () {
...
}(); // Syntax error!

(function () {
...
})(); // Bien

(function () {
...
}()); // Mejor. Queda más claro lo que estamos haciendo según Crockford

Usar siempre el “;”

Usar siempre el ; para evitar el Automatic Semicolon Insertion que puedo provocar bugs difíciles de depurar.

Algunos con los que puedo estar de acuerdo, pero debería revisar

Declaración de variables en el top

Como javascript no tiene (¿tenía?) block scope, si no sólo function scope, hay que declarar todas las variables en la parte de arriba y declarar todos los métodos antes de usarlos. Esto deja claro como funciona el hoisting en javascript que puede introducir errores. Esto incluye el no declarar variables dentro del for – for (var i …) {, para dejar claro que la variable i es válida para toda la función, y tiene valor antes (undefined) y después del for (el último valor que haya tomado en el bucle). Habría que ver como se conjuga esto con let, const, …

Espacio entre paréntesis y resto de elementos

Una serie de reglas sobre donde y como usar los paréntesis, del tipo:

  • No space before ( when used to invoke a function
  • No space between a function name and a parameter list
  • One space between all other names and (

Uso equivocado según crockford:

  • foo (bar);
  • function foo (b) {…}
  • function(x) {…}
  • return(a+b);
  • if (a=== 0) {…}

 


Charlas “The better Parts” por Douglas Crockford

Posted: mayo 28th, 2017 | Author: | Filed under: Sin categoría | Tags: , , , , , | No Comments »

Seguramente las charlas más conocidas de Crockford son las basadas en su libro The good parts y o algunas más modernas a las que llama de “The better parts” donde revisa alguna de sus anteriores prácticas y comenta features de ES6.

Dentro de esta serie de The Better Parts se pueden encontrar varias dadas en distintas momentos, entre ellas.

  • The Better Parts | .concat() 2015. El problema de esta charla es que no se ven las transparencias (y a pesar de ser similares) a las slides que usa en otras se hace un poco complicado seguir el hilo. Creo que una de las novedades de esta charla respecto a otra es cuando habla de los Template Literals.
  • The Better Parts. Infoq. Agosto/2014. Las transparencias de esta charla, que también valen de guía para el resto están aquí. La de la JSConfUY me pareció un poco más fluída que esta. Pero hay al menos dos secciones que en esta están mejor explicadas o ampliadas la que llama en las transaprecias New Good Parts in ES6 que empieza en el minuto 12 y acaba en el 25. Y cuando explica su constructor pattern (slide 46) a partir del minuto 34. El constructor también lo explica en la JSConfUY pero aquí se entienda mejor.
  • The Better Parts – JSConfUY Septiembre/2014. En apareciencia esta tiene un poco más de carga filosófica que la de Infoq.

Yo ví la charla de JSConfUY, ojee la de concat, y fuí a algunas partes concretas de la de InfoQ. Mi recomendación es que veas la de InfoQ. O si no que veas de la JSConfUY y las partes concretas que mencionó de la de InfoQ.

A nivel contenidos las charlas son similares.

Arranca con una cita de Saint-Exupéry, “It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to subtract.” y de como los programadores deben buscar la perfección. Por ello hace incapié en uno de sus habituales, que un lenguaje nos dé un montón de características no significa que tengamos que usarlas todas si no sólo las “buenas”.

Luego habla de jslint y de su libro de “The good parts”. Combate algunas de las criticas que se hacen de jslint y defiende porqué el estilo de desarrollo no es simplemente un “acuerdo”, si no que hay estilos mejores que otros, y que escribir de una determinada forma elimina bugs y por tanto te acerca a la perfección.

Continúa con una mini revisión de esas buenas partes de JavaScript en general mezclándolo con como debería ser el lenguaje del futuro (tiene otra charla sobre esto llamada The Post JavaScript Apocalypse), centrándose en su propuesta para un nuevo tipo de datos numérico llamado DEC64.

Y termina hablando un poco de JSON.

The better parts

Entre las prácticas que menciona como mejores están.

* No usar for. Sólo array.forEach y derivados
* No dice nada de for..of, supongo que en el momento todavía no habría una propuesta al respecto, pero si habla de evitar for..in y emplear unicamente Object.keys(object).forEach
* Y dice que tampoco usa ya while si no que usa una construcción de este tipo

1
2
3
4
5
function repeat(func) {
  if (func() !== undefined) {
    return repeat(func);
  }
}

Como vemos, y como el mismo dice, estás Better Parts van en la línea de usar JavaScript como un lenguaje funcional.

Especial atención merece su nuevo patrón para la construcción de objetos. Hace tiempo que aboga por no usar new pero también ha dejado de usar Object.create, de hecho ha dejado de usar this para evitar problemas de seguridad. También defiende que la herencia basada en prototipos es una mejor idea que las jerarquías clásicas. Porqué, las jerarquías son en general erróneas, y además suelen establecerse al principio del proyecto, cuando menos información se tiene de como debe ser.

Su patrón para la construcción de objetos tendría este aspecto

1
2
3
4
5
6
7
8
9
10
11
12
function constructor(spec) {
  let {member} = spec,
      {other} = other_constructor(spec),
      method = function () {
        // member, other, method
      };

  return Object.freeze({
      method,
      other
  });
}

Donde

  • spec será generalmente un object literal, que permite inicializar el objeto
  • member será un miembro privado de la clase, no accesible desde el exterior
  • Esta construcción permite que se pueden llamar tantas veces como se quiera a otros constructores (other_constructor), de ese modo se obtiene herencia múltiple, y se pueden copiar, las funciones de interés de esos otros objetos en nuestro objetos
  • También puedo crear nuevos métodos (method), que tendrán acceso a los miembros privados, a otros métodos, a lo que proporcione other. En este caso method es público porque se devuelve al llamante pero con el mismo diseño podría ser un método privado
  • Se devuelve un nuevo objeto (el literal dentro de freeze, con todos los métodos de interés)
  • Lo congela para hacerlo inmutable, con todas las implicaciones que eso trae. Seguridad, comparaciones más sencillas, …
  • Comenta que este sistema tiene un costo en memoria. Al contrario que otras estrategias que reaprovechan los métodos, en esta method sería creado cada vez. Pero a cambio es muy rápido, porque no hay que recorrer el prototype chain para encontrar las claves si no que están directamente en el propio objeto

En otro momento, me gustaría hacer un artículo con los distintos patrones de creación de objetos de Javascript, pero debo decir que este me convence mucho, porque debe ser de las pocas veces que veo algo de este tema en JS que parece tener sentido a la primera. Lo que no comprendo es porque llama “constructor” a su función de ejemplo cuando en realidad es una “factory”.


Recargar el navegador desde Emacs

Posted: mayo 21st, 2017 | Author: | Filed under: Sin categoría | Tags: , , , , , , , , | No Comments »

Aunque Emacs no suele aparecer entre los editores preferidos para desarrollo web sigue teniendo opciones que lo hacen interesante.

En este artículo vamos a comentar algunos “plugins” que nos ayudan a recargar el navegador automáticamente cuando hacemos cambios en el código. No todos funcionan en las últimas versiones de Emacs, pero los dejo en el artículo para saber lo que hay disponible, o al menos lo que no merece la pena probar.

Conclusiones

Para quien quiera ir directo al grano el que me parece más recomendable en este momento es Mini Kite Mode, que se comenta al final de listado y que descubrí a través de esta pregunta de stackoverlow. En las respuestas se mencionan algunos complementos para emacs para trabajar con desarrollo web que no he probado y que también podrían ser interesantes pero están todos desactualizados.

Listado de plugins

Impatient Mode

Uno de los limitantes de Impatient Mode es que hay que habilitar el impatient-mode por cada uno de los buffers que se quieran observar. Aunque supongo que se puede configurar de algún modo algún hook para que automáticamente habilite la observación en los buffers abiertos con determinadas extensiones.

Tras habilitar el modo

1
M-x impatient-mode

y lanzar el servidor

1
M-x httpd-start

tendremos en localhost un navegador que escuche los cambios

1
http://localhost:8080/imp/

Otro de sus problemas es que lo que parece hacer, es cargar dentro de un iframe la web que estamos editando en emacs, y desde el código html/js en el que está empotrado el frame se hace un pooling cada cierto tiempo para ver si el contenido cambia y recargar. Empotrar tu código dentro de un iframe al final excepto para casos sencillos puede ser problemático y el sistema de pooling tampoco es muy efectivo en la práctica, porque cada pocas pulsaciones de teclas se hace un refresco de la página.

Skewer Mode

Para hacer funcionar Skewer Mode seguramente haya que hacer un par de pruebas, pero hay un vídeo y una pregunta de stackexchange que pueden ayudar.

La parte interesante de este modo es que permite abrir un buffer en modo REPL para javascript. De modo que podemos evaluar el código js directamente en emacs como si estuvieramos usando la consola del navegador. O podemos editar nuestra fuente javascript y relanzar una función o porciones de código al navegador.

Uno de los mayores limitante es que la recarga no es automática, y en el modo html funciona tag a tag. Es decir, no podemos reenviar el buffer entero al navegador, si no sólo los tags que nos interesen. Lo que hace es modificar el dom, para actulizar el contenido de los tags. No lo he encontrado especialmente cómodo, pero tiene algunas extensiones que podrían simplificar el trabajo como skewer-less o skewer-reload-stylesheets.

Emacs browser refresh

Browser refresh es una idea sencilla e interesante. Basicamente usa xdotool, una herramienta que permite scriptear movimiento de ratón y pulsaciones de teclas, para poner la ventana del navegador en foco y pulsar “F5”, cuando le damos a salvar. El script original no funciona del todo bien, y aunque es fácil de arreglar es una solución “error prone”. Si tenemos varias ventanas del navegador abiertas, o hemos cambiado de pestaña puede funcionar incorrectamente.

GC Refresh Mode

De nuevo una buena idea pero el código de GC Refresh Mode está desactualizado y no funciona. Al activar el modo

1
M-x gc-refresh-mode

pregunta la url a recargar, que puede ser un http://localhost o un file:///, abre esa uri en chrome en modo remote-debugging y sobreescribe C-x C-s para que al recargar se ejecute un script en python. El script en python es una implementación muy sencilla del Chrome Debugging Protocol que conecta a un socket con el que comunicarse con la instancia del navegador que abrió antes, busca la pestaña donde está la uri de interés y la recarga.

El problema es que Chrome ya no usa exactamente este sistema y el script no funciona. Este plugin está inspirado en la página de Save And Reload Browser del Emacs Wiki.

chrome-reload-page

Basándose en la idea de GC Refresh Mode hace algún tiempo escribí un ejemplo de código (funcional) que acabó de subir a github.

Este script usa el Chrome debugging protocol para recargar la pestaña. El script lleva empotrado el código de python del fork de max-weller de chrome_remote_shell para ahorrar trabajo.

Mini Kite Mode

Mini Kite Mode es la más funcional de las opciones de este artículo.

Se puede instalar directamente desde MELPA. Para usarlo añadiremos a nuestro .emacs, las siguientes líneas.

1
2
3
4
5
6
(require 'kite-mini)
(require 'kite-mini-console)
# Automatically Turn on the mode for your buffer of choice.
(add-hook 'js-mode-hook (lambda () (kite-mini-mode t)))
(add-hook 'css-mode-hook (lambda () (kite-mini-mode t)))
(add-hook 'html-mode-hook (lambda () (kite-mini-mode t)))

El segundo require sólo es necesario si queremos abrir un buffer de Emacs como una consola js en modo REPL (similar a la consola de DevTools). Y los hooks permiten activar el modo para los buffers de interés en tener que activarlo a mano

1
M-x kite-mini-mode

Una vez en un buffer (y través a ver lanzado chrome / chromium en modo remote debug) simplemente conectamos con

1
M-x kite-mini-connect

Si la pestaña que tenemos abierta es con la que queremos interactual podemos simplemente pulsar intro. A partir de ese momento podemos lanzar la consola de js, enviar una región al navegador para que sea evaluada, o recargar la pestaña.

El mayor problema, de esta herramienta, y en realidad de todas las que usen el Remote Debug, es que sóla una herramienta puede estar conectada mediante el protocolo a la vez, y las DevTools hace uso de este sistema también. De modo que si kite está conectado y se abren las DevTools kite se desconectará. Y si son las DevTools las que estan activadas cuando hacemos kite-mini-connect, kite no llegará a conectar.

Para simplificar un poco el flujo he editado el fichero de ~/.emacs.d/elpa/kite-mini-20160508.406/kite-mini-el para que antes de hacer el reload salve el buffer, quedando así

1
2
3
4
5
6
(defun kite-mini-reload ()
  (interactive)
  (save-buffer)
  (kite-mini-call-rpc
   "Page.reload"
   (list :ignoreCache t)))

De este modo al pulsar C-c C-r, primero salva y luego recarga. El siguiente paso, sería que mientras esté conectado, pulsar C-x C-s salve el buffer y recargue, pero por ahora con esto me llega.


Modelado de datos booleanos en la base de datos

Posted: febrero 9th, 2017 | Author: | Filed under: Sin categoría | Tags: , , , , | No Comments »

Cuando definimos la información que un usuario puede visualizar o modificar a través de un formulario nos encontraremos datos aparentemente booleanos. Por ejemplo: ¿Hay un pozo en esta aldea?.

La primera aproximación para implementar esta información es poner un checkbox en el formulario y definir el campo como booleano en la base de datos.

1
CREATE TABLE aldea (id serial, pozo BOOLEAN);

Haciéndolo de este modo existen varios posibles problemas:

  • A nivel usabilidad. Que pasa si el usuario no sabe si hay un pozo. Lógicamente dejará el checkbox sin marcar, pero cuando se revise esa información no se podrá saber si a conciencia se dejo en blanco indicando que no había pozo, o si se desconocía el dato.
  • A nivel implementación. Por defecto, a no ser que la lógica implementada en cliente lo gestione de otra forma, en la base de datos almacenaremos un valor NULL y no un valor FALSE. Al tener valores nulos las queries que hagamos se pueden complicar, por ejemplo un SELECT * FROM aldea WHERE pozo IS FALSE; no nos devolverá los valores nulos. Si empleamos la tabla para hacer un informe o exportarla a una hoja de cálculo tendremos que lidiar con los nulos, …

Por tanto cuando modelemos una información que parezca binaria, preguntémonos (y preguntemos al cliente) si es necesario distinguir entre falso, y desconocer el dato. Si estamos en la segunda situación debemos huír de usar checkboxes y emplear otro tipo de widget, como un combobox donde el usuario pueda escoger “Existe”, “No existe” o dejar en blanco si no conoce el dato. A nivel implementación la información del combobox la guardaremos en general como un texto o un tipo enumerado. Y si eres un producto owner que usa algún tipo de documento para definir el modelo de datos a los desarrolladores asegurate siempre de especificar esta información.

Habrá situaciones en las que aún presentando al usuario la información mediante un combo, nos interese modelar el campo como un booleano. En este caso la lógica por encima de la base de datos sería la responsable de traducir el campo en blanco por un nulo, el ‘Existe’ por un true y el ‘No existe’ por un false.

Cuando modelemos un campo en la base de datos que sea verdaderamente binario para evitar confusiones deberíamos implementarlo de esta forma.

1
2
3
4
CREATE TABLE aldea (
id serial,
pozo BOOLEAN NOT NULL DEFAULT FALSE
)

Addendum

Cuando trabajamos con campos booleanos que admiten el valor nulo nos podemos encontrar un problema adicional al hacer migraciones de la base de datos. Imaginemos que tenemos un campo contador de tipo boolean, y que en la base de datos tenemos valores a true, false y null. Si a posteriori decidimos cambiar contador por un sistema de medida, con opciones como Contador, Manual, Volumétrico, … hacer la migración hacia adelante será sencillo.

1
UPDATE myschema.mytable SET sistema_medicion = 'Contador' WHERE contador IS TRUE;

Pero el revert no sería tan sencillo, porque habremos perdido la información de nulos y false.


DIY: Reparar el mando a distancia con papel albal

Posted: septiembre 30th, 2016 | Author: | Filed under: Sin categoría | Tags: , , , , , | No Comments »

Cuando el mando a distancia de la televisión tiene cierto uso no es raro que ciertos botones dejen de funcionar. Repararlo es más sencillo de lo que podría parecer.

La mayoría de teclados funcionan por el mismo principio. Un circuito impreso con una membrana por encima para cada tecla. En las membranas hay un conductor que al pulsar cierra el circuito produciendo una señal eléctrica que acaba enviando un código al receptor. A veces se introduce suciedad o se desgasta el conductor que cierra el circuito impidiendo que el botón funcione.

Para repararlo llega con abrir el mando a distancia e intentar limpiarlo o en caso de que no funcione usar papel albal (papel de aluminio). El papel albal es conductor, por tanto poniendo un pedacito con cuidado recubriendo la membrana estaremos “mejorando” la conductividad producida al pulsar la tecla.

Hay que tener cierto cuidado al abrir el mando, es fácil que el teclado se desalinee con el circuito impreso y al poner el albal. Sólo debe hacer contacto al pulsar la tecla, por lo que se puede usar una gotita de pegamento para pegarlo a la membrana.

Olvidé tomar fotos del proceso y con estos mandos de plástico abrir y cerrar a menudo no es buena idea pero en internet hay muchos ejemplos del paso a paso.

Antes de tirarte de cabeza a comprar un nuevo objeto porque tenga poco coste, recuerda la regla de las cinco erres.


Usando GeoProcesos en gvSIG desde Java

Posted: septiembre 4th, 2016 | Author: | Filed under: Sin categoría | Tags: , , , , , , , , | No Comments »

La semana pasada había un correo en la lista de desarrollo de gvSIG preguntando como poder lanzar geoprocesos desde tu propio plugin mediante Java. Tras una pequeña investigación he escrito un código de ejemplo que espero que sea útil a quien tenga esta necesidad.

Descargar el código

A mi particularme me gusta descargar el código fuente de las partes de gvSIG con las que voy a trabajar. Esto simplifica el usar las herramientas del IDE para saber como usarlo, encontrar errores, y revisar los tests, en caso de haberlos, para tener pistas de como escribir mi propio código.

Para ello primero se mira la versión del plugin que se corresponda con la versión de gvSIG que estás usando. Creo que lo más fácil es descargar una versión portable de gvSIG. Entrar a la carpeta que contiene el plugin, en este caso org.gvsig.geoprocess.app.mainplugin y abrir el fichero package.info. En la property version está el tag del repo correspondiente a esa versión. Por ejemplo para la 2.3RC2 sería el 2.266. Por tanto para descargar el repo haremos:

1
svn checkout http://devel.gvsig.org/svn/gvsig-geoprocess/org.gvsig.geoprocess/tags/org.gvsig.geoprocess-2.2.66/

A continuación,e n caso de usar Eclipse, iremos a import -> Existing maven projects, e importaremos la raíz del nuevo plugin descargado.

Añadir las dependencias

Al desarrollar en gvSIG debemos tener en cuenta que las dependencias de nuestro plugin, por decirlo de algún modo, serán de dos tipos. En “Tiempo de desarrollo”, y en “Tiempo de ejecución”. Las dependencias en desarrollo se definen en el pom del proyecto permitiéndonos definir el classpath de desarrollo para trabajar con las clases que nos hagan falta.

En ejecución, cuando estamos probando o ejecutando gvSIG, el classpath se define de manera dinámica por decirlo de algún modo en el fichero de config.xml. gvSIG buscará entre las dependencias que hayamos definido en el config las clases que se pueden usar en nuestro plugin.

Para que quede claro, a nuestro pom se añadirán otros proyectos maven. A nuestro config se añadirán plugins de gvSIG.

Por ejemplo para el caso de usar los geoprocesos, añadiremos al pom:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
    <groupId>org.gvsig</groupId>
    <artifactId>org.gvsig.geoprocess.lib.api</artifactId>
    <version>2.2.66</version>
</dependency>

<dependency>
    <groupId>org.gvsig</groupId>
    <artifactId>org.gvsig.geoprocess.lib.sextante</artifactId>
    <version>2.2.66</version>
</dependency>

y al config

1
<depends plugin-name="org.gvsig.geoprocess.app.sextante"/>

Obtener el algoritmo que queremos

Esta una de las partes en las que tengo más dudas que esté correcta.

En general accederemos a las funcionalidades de gvSIG a través de un Locator que nos dará un Manager que nos dará la funcionalidad. En el caso de los geoprocesos sería:

1
2
3
4
String ALG_NAME = "gvSIG-intersection";
SextanteGeoProcessManager manager = (SextanteGeoProcessManager) GeoProcessLocator.getGeoProcessManager();
HashMap<String, GeoAlgorithm> algs = manager.getAlgorithms();
GeoAlgorithm alg = algs.get(ALG_NAME);

Debemos castear a la implementación por defecto del manager SextanteGeoProcessManager porque la interfaz en sí no proporciona el método getAlgorithms. Esto diría que es un bug.

La forma de obtener ALG_NAME, no estoy seguro de cual es. En principio lo más fácil sería poner un breakpoint y mirar los valores de algs. Aunque en mi caso sólo salen los propios de gvSIG y no los de Sextante.

Seteando valores al algoritmo

Todos los algoritmos definen un método defineCharacteristics que nos indican los valores que recibe, tanto de entrada como de salida. Esta definición de valores se obtiene a través del método getParameters

En nuestro código debemos obtener cada uno de los parámetros necesarios y setear su valor real para nuestro caso. Por ejemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void setParams(GeoAlgorithm alg) throws WrongParameterIDException {
    ParametersSet params = alg.getParameters();

    FLyrVect interLyr = getLayer("inter");
    FlyrVectIVectorLayer inter = new FlyrVectIVectorLayer();
    inter.create(interLyr);

    FLyrVect layerLyr = getLayer("layer");
    FlyrVectIVectorLayer layer = new FlyrVectIVectorLayer();
    layer.create(layerLyr);

    params.getParameter(IntersectionAlgorithm.INTER).setParameterValue(
            inter);
    params.getParameter(IntersectionAlgorithm.LAYER).setParameterValue(
            layer);
    params.getParameter(IntersectionAlgorithm.SELECTGEOM_INPUT)
            .setParameterValue(false);
    params.getParameter(IntersectionAlgorithm.SELECTGEOM_OVERLAY)
            .setParameterValue(false);
}

En este caso para no escribir a mano los idenfificadores de los parámetros uso las variables estáticas definidas en el propio algoritmo. Eso hace que haya que añadir al pom el algortimo:

1
2
3
4
5
<dependency>
    <groupId>org.gvsig</groupId>
    <artifactId>org.gvsig.geoprocess.algorithm.intersection</artifactId>
    <version>2.2.66</version>
</dependency>

Para las capas de entrada al algoritmo hay que generar una FlyrVectIVectorLayer. Como se muestra en el código de ejemplo lo más sencillo es obtener un FLyrVect y construirla con el create.

Ejecutando el algoritmo

Los algoritmos se lanzan mediante el método execute que como indica la documentación admite hasta tres parámetros.

  • ITaskMonitor task. Que puede ser nulo y permite monitorizar el estado para por ejemplo poner una barra de progreso al usuario
  • HashMap outputMap. Que permite modificar los nombres que sextante asigna a los parámetros de salida (en general capas)
  • OutputFactory outputFactory. Define como se crearán los objetos de salida. Puede ser nuestra propia implementación o usar la factoría por defecto

Por tanto ejecutarlo sería simplemente:

1
alg.execute(null, new DefaultOutputFactory(), null);

Obteniendo los resultados

Con la factoría por defecto las capas se crean en un directorio temporal que en linux es /tmp/tmp-andami y les asigna nombres aleatorios (creo que basados en el timestamp). Supongo que habrá alguna utilidad que nos permite ejecutar una especie de FinalActions para añdirlos automáticamente a la vista. O implementando nuestra propia OutputFactory podríamos definir otras rutas. También diría que podemos prescindir del OutputFactory y lanzar el algoritmo mediante processAlgorithm si igual que hicimos con los parámetros de entrada seteamos adecuadamente los valores de salida, especialmente el OutputChannel de las capas.

En todo caso el método getOutputObjects nos devuelve los objetos de salida, así por ejemplo podríamos llegar el FlyrVectIVectorLayer de la capa de polígonos de salida con:

1
2
3
OutputObjectsSet outputSet = alg.getOutputObjects();
OutPut output = outputSet.getOutPut(IntersectionAlgorithm.RESULT_POL)
FlyrVectIVectorLayer result_pol = (FlyrVectIVectorLayer) output.getOutputObject();

Si el disco duro no para al arrancar ubuntu vacía la papelera

Posted: agosto 7th, 2016 | Author: | Filed under: Sin categoría | Tags: , , , , , , | No Comments »

Los discos duros (casi) infinitos actuales han hecho que en un año haya acumulado más de 4000 ficheros y casi 60GB en la papelera de Gnome. Nunca pensé que esto fuera un problema pero ultimamente el ordenador tardaba muchísimo en iniciarse y el disco duro incluso después de arrancar el escritorio estaba funcionando durante uno o dos minutos.

El comando iotop nos permite saber que procesos están consumiendo más acceso a disco, y al lanzarlo durante el arranque descubrí que el problema era el servicio gvfsd-trash, responsable de la gestión de la papelera. Hay un montón de bugs y comentarios en los foros quejándose de este problema [1], [2], [3].

A falta de una solución mejor simplemente vaciar la papelera funciona. Así que ya sabes, si la lucecita del disco duro no para durante el arranque vacia la papelera.


Cliente de correo para Linux

Posted: mayo 15th, 2016 | Author: | Filed under: Sin categoría | Tags: , , | No Comments »

Llevo usando aplicaciones web para usar el correo desde que abrí mi primera cuenta de mail. Gmail tiene tiene una interfaz genial, funciona en cualquier dispositivo y es rápido. El único problema es que tus correos no son tuyos. Estos días he tenido que cerrar una vieja cuenta de correo en gmail y para descargar los mails a modo de copia de seguridad he estado revisando clientes de correo de escritorio:

  • Que se lleven bien con gmail/imap, respetando etiquetas, …
  • Que permitan agrupar conversaciones al modo en que lo hace gmail
  • Que tenga buenas funcionalidades de búsqueda
  • Que no use Qt

En las recomendaciones y quejas de clientes sobresalen un par de ellos:

  • Claws Mail. Que no parece tener el “modo conversación”
  • N1. Que tiene una pintaza, algo así como el Atom de los clientes de correo, el problema es que todo el correo pasa a través de sus servidores o tienes que instalar uno en local.
  • Evolution. Que parece pesado, poco documentado y con demasiada gente quejándose de bugs.
  • Thunderbird.
  • Geary.

Tanto Thunderbird (con plugins) como Geary (por diseño) cumplen todos los requisitos, pero la búsqueda de Thunderbird parece mejor, y la mayor base de usuarios y documentación hace que sea el que vaya a probar.

Siguiendo la documentación de thunderbird, la documentación sobre IMAP de Google es fácil de configurar. Si hay problemas de conexión se puede deshabilitar el acceso seguro en google o habilitar OAuth2 en thunderbird como método de autenticación.

Para configurarlo bien hay que revisar un poco la configuración pero en general funciona todo sin problemas.


Atom: Autocompletado de código en python

Posted: mayo 8th, 2016 | Author: | Filed under: Sin categoría | Tags: , , , , | No Comments »

Al margen del “Code Completion” de PyCharm, y algún otro, el resto de editores/IDEs proveen autocompletado a través de librerías o “servicios externos”. Para el caso de python hay fundamentalmente dos, rope y jedi. Rope está más enfocada a Refactoring y Jedi a Autocompletado, por tanto las dos son complementarias. En la actualidad varios editores que usaban rope están migrando a jedi, su autor ha hecho una comparación defendiendo su librería.

Además de estas librerías cada editor suele proporcionar un plugin base para autocompletado (autocomplete-plus en atom, auto-complete en emacs) y plugins adicionales para cada lenguaje concreto que actúan como wrapper de las librerías base (rope, jedi,…). Por ejemplo en atom tenemos autocomplete-python que es un wrapper para jedi.

Instalación

Primero hay que instalar jedi sea a nivel global como en el ejemplo, o dentro de un virtualenv.

1
sudo pip install jedi

Luego se instala el plugin de autocomplete-pyhon (que es el más actualizado de los varios que hay). Si usas virtualenv también debería funcionar sin problemas pero si usas algo como virtualenvwrapper donde tu módulo está en un directorio distinto al “entorno virtual de python” puedes haber más problemas.

Lanzado atom desde un virtualenv activado siempre funciona correctamente. Si lo lanzas de otra forma hay que configurar la opción de configuración Python executable path del plugin con algo como:

1
2
3
4
5
PATH_TO_VIRTUALENV_WRAPPERS_FOLDER/$PROJECT_NAME/bin/python

o

PATH_TO_VIRTUALENV_WRAPPERS_FOLDER/$PROJECT/bin/python

Donde PATH_TO_VIRTUALENV_WRAPPERS_FOLDER es la ruta absoluta al directorio donde se guardan todos los entornos virtuales de virtualenwrapper y $PROJECT_NAME y $PROJECT son cadenas que debes escribir tal cual. Son variables que entiende el plugin. De la documentación parece deducirse que lo que hay que usar es $PROJECT pero a mi me ha funcionado sólo con $PROJECT_NAME. Además el directorio padre que se añade a atom a través del “Add project folder” debería llamarse igual que el virtualenv para que $PROJECT_NAME tome el valor correcto y puedas usar la misma configuración para distintos proyectos.

Uso

Por la naturaleza dinámica de python muchas veces jedi no es capaz de detectar el tipo de datos de un objeto. Pero podemos ayudarlo documentado el método. Por ejemplo en un caso como el del ejemplo siguiente con una vista de pyramid, jedi no será capaz de determinar el tipo de datos del parámetro request.

1
2
3
@view_config(route_name='my_route')
def my_route(request):
  pass

Pero si hacemos lo siguiente si que autocompletará correctamente los métodos de request:

1
2
3
4
5
def cultivos_get(request):
    """
    :type request: pyramid.request.Request
    """

    pass

No lo he probado con python 3 para ver si soporta el type hinting pero este issue me hace suponer que si.
Teclas principales

  • Sugerencias de autocompletado.
    1
    Ctrl+space

    Cursores y tab/intro para escoger y aceptar sugerencia

  • Go to definition:
    1
    Ctrl+Alt+G
  • Show usages:
    1
    Ctrl+Shift+P show usages
  • Renombrado en varios ficheros a la vez: Con el cursor encima del símbolo.
    1
    Ctrl+Shift+P rename

Conclusiones

Las funcionalidades que proporciona son de todas formas muy justas porqué a no ser que documentes los métodos, la mayoría de veces no es capaz de inferir el tipo de datos de una variable. Además las funciones de autocompletado normal de atom incluyen habitualmente opciones que no tienen porque corresponder con métodos o propiedades reales del objeto. Y si se desactiva el autocompletado normal para los ficheros python, tendremos muy pocas sugerencias.