Saltar a contenido

2011

Dan Pink en la sorprendente ciencia de la motivación

Sergio me pasa un vídeo que da los puntos básicos sobre como debería ser una gestión empresarial moderna. Promoción horizontal, incentivos, gestión, productividad, … son temas de moda sobre los que espero seguir escribiendo pero las premisas básicas son fáciles de condensar:

Cuando las tareas a realizar involucran sólo habilidades mecánicas los incentivos económicos funcionan muy bien. A mayor recompensa mayor rendimiento.

Pero en general una vez alcanzado un incentivo económico razonable, un aumento de este en forma de recopensa no se traduce en un mayor rendimiento, si no que de hecho, en muchas ocasiones reduce la productividad.

La motivación extrínseca (como el dinero) sólo funciona para alcanzar cierto nivel de rendimiento, a partir de ese nivel la motivación intrínseca es más importante. Por tanto, los incentivos otorgados para incrementar el rendimiento deberían basarse en estas tres premisas

  • Autonomía: El impulso de dirigir nuestra propia vida. Mientras que la gestión tradicional funciona cuando lo que necesitas es conformismo, otorgar autonomía tiende a funcionar cuando lo que necesitas es autonomía.
  • Maestría: El deseo de ser mejor y mejor en algo que importa
  • Propósito: El deseo de hacer lo que hacemos al servicio de algo más grande que nosotros mismos

Comentario sobre el diseño de bases de datos PostGIS

Un par de comentarios muy rápidso sobre una práctica que considero acertada a la hora del diseño con bases de datos PostGIS.

No uses el esquema public

PostGIS emplea de forma intensiva el esquema public para crear funciones, tipos de datos etc… Si tu también empleas ese esquema cuando vuelques tu base de datos ese esquema tendrá que ser incluído y no sólo irán tus datos si no también toda la parte de PostGIS lo que incrementará el tamaño del dump y el tiempo de restauración.

Además si el usuario quiere restaurar la bd sobre una ya existente con PostGIS saldrán un montón de errores de que las funciones ya existen, con lo que se hace difícil depurar otros posibles errores. También se pueden producir errores si tu dump corresponde a una versión de PostGIS distinta a la que tiene el usuario.

Cuando vuelques tu base de datos excluye el esquema public del volcado

Por lo ya explicado en el punto 1. Hacer esto es tan sencillo como:

<br></br>pg_dump --no-owner -N public -h servidor -U usuario -f /tmp/base_de_datos.sql base_de_datos<br></br>

Vuelca también la tabla geometry_columns

Los únicos datos que estarán en el esquema público que te hacen falta serán los de la tabla geometry_columns. Vuelca por tanto esos datos (no hace falta la estructura) a otro fichero sql.

<br></br>pg_dump --no-owner -a -t geometry_columns -h servidor -U usuario -f /tmp/geometry_columns.sql base_de_datos<br></br>

Teniendo en cuenta estos consejos apenas tendrás trabajo extra y harás la vida mucho más fácil a quien tenga que restaurar la base de datos (que puede que seas tu mismo)

Actualización 17/Febrero/2013. Acabo de encontarme por primera vez desde que escribí esto con alguien que también declara en un post lo importante de no usar el schema public cuando se trabaja con postgis.

Um curso objetivo de programação em Python

Gracias al blog de Anderson Medeiros encuentro un interesante tutorial de python escrito en Portugués pero muy facilito de seguir.

Es un tutorial de introducción, rápido de leer y que me ha ayudado a recordar algunos de esos conceptos que por estar más habituado a otros lenguajes tipo Java no empleas a menudo.

Algunas cosillas que he recordado, aprendido o me han gustado.

Listas, tupas y strings

Explica bien que son listas, tuplas, diccionarios y strings. A listas y tuplas se las llama en ocasiones secuencias puesto que sus propiedades son muy parecidas. Una tupla es en realidad una lista inmutable.

Conviene tener en la cabeza lo fácil que es hacer slices (subconjuntos de secuencias) y substrings en python, incluso empleando índices negativos para empezar a contar por el final. LLega con escribir:
<br></br>>>> lista = ['a', 'b', 'c', 'd', 'e', 'f', 'g']<br></br>>>> lista[2:5]<br></br>['c', 'd', 'e']<br></br>>>> lista[2:]<br></br>['c', 'd', 'e', 'f', 'g']<br></br>>>> lista[:5]<br></br>['a', 'b', 'c', 'd', 'e']<br></br>>>> lista[:-2]<br></br>['a', 'b', 'c', 'd', 'e']<br></br>>>> lista[-2:]<br></br>['f', 'g']<br></br>

Los operadores * y + se pueden usar sobre listas, tuplas y strings. * replica n veces el elemento y + concatena.

Ejemplo para strings:
<br></br>>>> a = "exato"<br></br>>>> print a * 2<br></br>exatoexato<br></br>>>> print "quase " + a<br></br>quase exato<br></br>
Ejemplo para listas:
<br></br>>>> a = [-1, 0]<br></br>>>> b = [1, 2, 3]<br></br>>>> print b * 3<br></br>[1, 2, 3, 1, 2, 3, 1, 2, 3]<br></br>>>> print a + b<br></br>[-1, 0, 1, 2, 3]<br></br>

Para chequear si un elemento está contenido en una secuencia o diccionario se usa el operador in
<br></br>>>> "x" in "cha"<br></br>False<br></br>>>> 1 in [1,2,3]<br></br>True<br></br>

Combinar de forma implícita operaciones lógicas

Además de los operadores lógicos not, or, and python permite combinar ciertas operaciones lógicas de forma implícita:

Por ejemplo podemos comprobar un número está en un determinado rango de esta forma:
<br></br>a = 5<br></br>if 3 < a < 9:<br></br> print "Entre 3 y 9"

a = 3; b = 3; c = 2;
if a == b <= c:
print "a igual a b y b menor o igual que c"

Clausula else en bloques for y while

En los for y los while se puede emplear una claúsula else que se ejecutará cuando se salga del bloque de iteración por haber acabado la secuencia (en lugar de salir por un break)
<br></br>valores = [2, 4, 5, 2, -1]<br></br>for i in valores:<br></br> if i < 0:<br></br> print "Negativo encontrado: %d" %i<br></br> break<br></br>else:<br></br> print "Nenhum negativo encontrado"<br></br>

Valores booleanos

No está de más recordar que en python se considera falso a:

  • el booleano False
  • el valor 0 (zero)
  • una lista, diccionario, tupla o string vacios (de tamaño cero)
  • el valor especial None

Así por ejemplo para comprobar si una lista no está vacía mejor que emplear
<br></br>lista = ['a']<br></br>if (len(lista)) != 0:<br></br> print "forma poco apropiada de comprobar si una lista no está vacia"<br></br>
usaremos directamente
<br></br>if lista:<br></br> print "Lista no vacia"<br></br>

Argumentos de funciones

Existen dos formas de pasar un número variable de argumentos a una función:
<br></br>def desculpa(alvo, *motivos):<br></br> d = "Desculpas %s, mas estou doente" % alvo<br></br> for motivo in motivos:<br></br> d = d + " e %s" % motivo<br></br> return d + "."

>>> desculpa("senhor", "meu gato fugiu",
... "minha tia veio visitar")

o bien
<br></br> def equipe(diretor, produtor, **atores):<br></br> for personagem in atores.keys():<br></br> print "%s: %s" % (personagem, atores[personagem])<br></br> print "-" * 20<br></br> print "Diretor: %s" % diretor<br></br> print "Produtor: %s" % produtor

>>> equipe(diretor="Paul Anderson",
... produtor="Paul Anderson",
... Frank="Tom Cruise", Edmund="Pat Healy",
... Linda="Julianne Moore")

Frank: Tom Cruise
Edmund: Pat Healy
Linda: Julianne Moore
--------------------
Diretor: Paul Anderson
Produtor: Paul Anderson

Si tienes algún tutoirial de python que te haya gustado o algún truquillo que quieres compartir deja un comentario.

Preparar un ordenador con Windows para asistir al curso de OpenLayers.

Un par de instrucciones rápidas para el curso de OpenLayers que habrá mañana en la Escuela de Caminos en Coruña impulsado por xeoinquedos, No te asustes por el texto es mucho más fácil de lo que parece. En resumen baja los archivos que se enlazan en este post y haz doble click sobre ellos :) Los enlaces son para Windows de 32bits, si usas 64 deja un comentario y te ayudamos.

1.- Instalar Apache.

La forma más sencilla es descargar Xampp desde esta dirección [1] e instalarlo haciendo doble click. Las opciones que trae por defecto son adecuadas para la mayoría de los equipos.

Para lanzar Apache ejecuta el acceso directo que aparece en tu escritorio y luego pulsa en el botón «Start» que está a la derecha de Apache. Si salta un mensaje del antivirus pulsa en desbloquear. Para comprobar que funciona abre un navegador y escribe en la barra de direcciones http://localhost

Si se abre una página naranja ya lo tienes :)

Si tienes algún problema, tienes instrucciones más detalladas en este enlace [3]

2.- Instalar un intérprete de Python

Descarga python 2.7.1 para windows desde este enlace [2]. Instálalo mediante doble click, las opciones por defecto son una vez más adecuadas para la mayoría de los equipos.

3.- Instalar python como módulo cgi para Apache.

Descárgate este fichero [4] y cópialo dentro de la carpeta c:xamppapachemodules. Cámbiale el nombre de mod_wsgi-win32-ap22py27-3.3.so a mod_wsgi.so

A continuación abre con el WordPad el fichero c:xamppapacheconfighttpd.conf Localiza el conjunto de líneas que empiezan por el texto LoadModule y añade al final

LoadModule wsgi_module modules/mod_wsgi.so

Salva el fichero y vuelve a probar si funciona Apache.

4.- Firebug.

Lo mejor es que traigas instalado un navegador como firefox con el complemento firebug. Para instalar firebug simplemente pincha en este enlace [5] desde firefox y sigue las instrucciones.

Si usas firefox 3.6 debes descargar la versión 1.6, si usas firefox 4 debes usar la 1.7 preferiblemente. Para saber que versión de firefox tienes instalada pincha en Ayuda -> Acerca de

Aviso: En este momento la página de firebug parece caida así que si no funciona prueba con este otro enlace [8]

5.- Editor de texto

Con el bloc de notas o el WordPad es suficiente para lo que vamos a hacer pero si quieres instalar uno más potente puedes probar notepad++ [9]

6.- Copia el archivo proxy.cgi que se proporciona en los materiales del curso al directorio c:xamppcgi-bin

Y listo. Como es habitual en estas cosas, esto más difícil de escribir que de hacer.

Por último agradecer a Micho, Xurxo, Gracia, Cartolab y la Escuela de Caminos, sin los que esté curso no sería posible.

Como usar GIT tras no haber seguido el flujo de trabajo idóneo

GIT es una herramienta genial cuando eres un desarrollador disciplinado y sigues el flujo de trabajo recomendado:

<br></br>$ git checkout -b nuevaFuncionalidad<br></br>... programar<br></br>$ git add -u # añadimos automaticamente todos los ficheros indexados que han sido modificados<br></br>$ git add fichero # añadimos los no indexados<br></br>$ git commit -m "Mensaje del commit"<br></br>... más commits<br></br>$ git checkout master<br></br>$ git pull --rebase<br></br>$ git checkout nuevaFuncionalidad<br></br>$ git rebase master<br></br>... (solucionar posibles conflictos)<br></br>$ git checkout master<br></br>$ git rebase nuevaFuncionalidad<br></br>$ git push<br></br>
Pero si hay algo que me gusta, y aquí se nota que es una herramienta hecha por desarrolladores para desarrolladores, es lo bien que se comporta cuando no eres tan disciplinado o has metido la pata. Vayamos con un ejemplo (casi) real que se inicia con un viaje en tren Coruña – Vigo.

El estado del repositorio al empezar era este:

<br></br># On branch master<br></br># Your branch is ahead of 'origin/master' by 1 commit.<br></br>#<br></br># Changes to be committed:<br></br># (use "git reset HEAD ..." to unstage)<br></br>#<br></br># modified: config/text_en.properties<br></br># modified: config/text_es.properties<br></br># modified: config/text_gl.properties<br></br># new file: src/es/udc/cartolab/gvsig/tocextra/ReloadVectorialDBLayerTocMenuEntry.java<br></br>#<br></br># Untracked files:<br></br># (use "git add ..." to include in what will be committed)<br></br>#<br></br># bin/<br></br>

Se trata de la extensión para gvSIG, extTOCextra desarrollada inicialmente por Javi y liberada por Cartolab como parte del proyecto gvSIG-EIEL. Como vemos en algún momento del pasado se hizo un commit directamente sobre master que no se subió al repositorio y tenemos cuatro ficheros preparados para hacer un commit que todavía no se ha hecho.

En el viaje de vuelta Vigo – Coruña, nuestro desarrollador se pone a acabar lo que había empezado a la ida, hace un git status y se encuentra que el estado del repositorio es este:
<br></br># On branch master<br></br># Your branch is ahead of 'origin/master' by 1 commit.<br></br>#<br></br># Changes to be committed:<br></br># (use "git reset HEAD ..." to unstage)<br></br>#<br></br># modified: config/text_en.properties<br></br># modified: config/text_es.properties<br></br># modified: config/text_gl.properties<br></br># new file: src/es/udc/cartolab/gvsig/tocextra/ReloadVectorialDBLayerTocMenuEntry.java<br></br>#<br></br># Changed but not updated:<br></br># (use "git add ..." to update what will be committed)<br></br># (use "git checkout -- ..." to discard changes in working directory)<br></br>#<br></br># modified: .classpath<br></br># modified: config/text_es.properties<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/ShowActivesTocMenuEntry.java<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/TocExtraExtension.java<br></br>#<br></br># Untracked files:<br></br># (use "git add ..." to include in what will be committed)<br></br>#<br></br># bin/<br></br># src/es/udc/cartolab/gvsig/tocextra/preferences/<br></br>
A base de memoria y git diff sabemos que:

  • El commit ya realizado y los archivos preparados para hacer commit constituyen una nueva funcionalidad (funcionalidad 1) que no nos interesa subir al repo por ahora
  • La modificación del .classpath y parte de lo modificado en TocExtraExtension son una pequeña refactorización que tiene sentido en si misma y que nos interesa subir como un commit separado del resto
  • El nuevo paqueta es.udc.cartolab.gvsig.tocextra.preferences, y los cambios ShowActivesTocMenuEntry, text_es.properties, y parte de los de TocExtraExtension son parte de una nueva funcionalidad (funcionalidad 2) que se empezó a programar y que todavía no está terminada. Así que nos interesa tenerla en una rama disinta de master para poder seguir trabajando sobre ella.

A la vista de esto nuestro objetivo será:

  • Tener una nueva rama con la funcionalidad 1 conservando la diferencia entre el commit ya realizado y el que tenemos preparado.
  • Una rama nueva con la refactorización en un sólo commit para luego traérnosla a master (tras haber sincronizado master con el repo) y subirla
  • Una rama nueva con la funcionalidad 2 en tantos commits como queramos para seguir trabajando.

Para conseguirlo tenemos muchos caminos alternativos, provemos uno en el que usemos distintos comandos que nos permitan ver la potencialidad de git.

Acabamos el commit que tenemos preparado

$ git commit -m "i18n for ReloadVectorialDBLayerTocMenuEntry"

Ocultamos temporalmente los cambios que nos quedan para que no nos molesten, creamos una nueva rama para la funcionalidad 1, y limpiamos el master.

<br></br>$ git status<br></br># On branch master<br></br># Your branch is ahead of 'origin/master' by 2 commits.<br></br>#<br></br># Changed but not updated:<br></br># (use "git add ..." to update what will be committed)<br></br># (use "git checkout -- ..." to discard changes in working directory)<br></br>#<br></br># modified: .classpath<br></br># modified: config/text_es.properties<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/ShowActivesTocMenuEntry.java<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/TocExtraExtension.java<br></br>#<br></br># Untracked files:<br></br># (use "git add ..." to include in what will be committed)<br></br>#<br></br># bin/<br></br># src/es/udc/cartolab/gvsig/tocextra/preferences/<br></br>$ git stash<br></br># On branch master<br></br># Your branch is ahead of 'origin/master' by 2 commits.<br></br>#<br></br># Untracked files:<br></br># (use "git add ..." to include in what will be committed)<br></br>#<br></br># bin/<br></br># src/es/udc/cartolab/gvsig/tocextra/preferences/

$ git checkout -b reloadDBLayers
$ git checkout master
$ git reset -hard HEAD^^ # Devolvemos la rama master al estado que tenía hace dos commits, es decir, eliminamos los cambios en local

Creamos una nueva rama para la refactorización y deshacemos la ocultación

<br></br>$ git checkout -b refactor<br></br>Switched to a new branch 'refactor'<br></br>$ git stash apply<br></br>Auto-merging .classpath<br></br>CONFLICT (content): Merge conflict in .classpath<br></br>Auto-merging config/text_es.properties<br></br>CONFLICT (content): Merge conflict in config/text_es.properties<br></br>$ git st<br></br># On branch refactor<br></br># Changes to be committed:<br></br># (use "git reset HEAD ..." to unstage)<br></br>#<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/ShowActivesTocMenuEntry.java<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/TocExtraExtension.java<br></br>#<br></br># Unmerged paths:<br></br># (use "git reset HEAD ..." to unstage)<br></br># (use "git add/rm ..." as appropriate to mark resolution)<br></br>#<br></br># both modified: config/text_es.properties<br></br>#<br></br># Untracked files:<br></br># (use "git add ..." to include in what will be committed)<br></br>#<br></br># bin/<br></br># src/es/udc/cartolab/gvsig/tocextra/preferences/<br></br>
Ups, el stash apply nos ha provocado un conflicto. ¿Por qué?. Tómate 15 sg para pensarlo y luego sigue leyendo…

En el commit que teniamos sin hacer había modificaciones sobre text_es.properties, cuando lo comiteamos dejamos algunas modificaciones sobre ese archivo que estaban basadas en los cambios comiteados. Como la rama «refactor» la creamos a partir de un master limpio, sin esas modificaciones cuando ejecutamos stash apply ese fichero se encuentra en un estado distinto al esperado y se produce un conflicto que no es capaz de resolver automáticamente. Si hubieramos creado la rama refactor a partir de la rama reloadDBLayers el conflicto no se hubiera producido, pero en esa rama hay cambios que no nos interesan por lo que no podemos hacer esto.

Tras la solución del conflicto el estado de repo es este:
<br></br># On branch refactor<br></br># Changed but not updated:<br></br># (use "git add ..." to update what will be committed)<br></br># (use "git checkout -- ..." to discard changes in working directory)<br></br>#<br></br># modified: .classpath<br></br># modified: config/text_es.properties<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/ShowActivesTocMenuEntry.java<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/TocExtraExtension.java<br></br>#<br></br># Untracked files:<br></br># (use "git add ..." to include in what will be committed)<br></br>#<br></br># bin/<br></br># src/es/udc/cartolab/gvsig/tocextra/preferences/<br></br># no changes added to commit (use "git add" and/or "git commit -a")<br></br>

Separar los cambios realizados sobre TocExtraExtension.java

Como los cambios de la refactorización para el archivo TocExtraExtension.java están mezclados con los de la funcionalidad 2, usaremos la opción –patch de git add para separarlos separarlos. Esto nos permitirá escoger que cambios (hunks) de un archivo queremos preparar para comitear en lugar de añadir todo el archivo.
<br></br>$ git add -i src/es/udc/cartolab/gvsig/tocextra/TocExtraExtension.java<br></br>$ git status<br></br># On branch refactor<br></br># Changes to be committed:<br></br># (use "git reset HEAD ..." to unstage)<br></br>#<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/TocExtraExtension.java<br></br>#<br></br># Changed but not updated:<br></br># (use "git add ..." to update what will be committed)<br></br># (use "git checkout -- ..." to discard changes in working directory)<br></br>#<br></br># modified: .classpath<br></br># modified: config/text_es.properties<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/ShowActivesTocMenuEntry.java<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/TocExtraExtension.java<br></br>#<br></br># Untracked files:<br></br># (use "git add ..." to include in what will be committed)<br></br>#<br></br># bin/<br></br># src/es/udc/cartolab/gvsig/tocextra/preferences/<br></br>$ git add .classpath<br></br>$ git commit -m "Small refactor"<br></br>[refactor 715b4da] Small refactor<br></br> 1 files changed, 18 insertions(+), 14 deletions(-)<br></br>
Como se puede ver, hemos hecho commit de sólo una parte de los cambios realizados en TocExtraExtension. Los cambios que quedan son todos los de la funcionalidad 2, así que los comiteamos a una nueva rama
<br></br>$ git checkout -b newFeature<br></br>M config/text_es.properties<br></br>M src/es/udc/cartolab/gvsig/tocextra/ShowActivesTocMenuEntry.java<br></br>M src/es/udc/cartolab/gvsig/tocextra/TocExtraExtension.java<br></br>Switched to a new branch 'newFeature'<br></br>$ git add -u<br></br>$ git add src/es/udc/cartolab/gvsig/tocextra/preferences/<br></br>$ git status<br></br># On branch newFeature<br></br># Changes to be committed:<br></br># (use "git reset HEAD ..." to unstage)<br></br>#<br></br># modified: config/text_es.properties<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/ShowActivesTocMenuEntry.java<br></br># modified: src/es/udc/cartolab/gvsig/tocextra/TocExtraExtension.java<br></br># new file: src/es/udc/cartolab/gvsig/tocextra/preferences/TOCExtraPreferencesPage.java<br></br>#<br></br># Untracked files:<br></br># (use "git add ..." to include in what will be committed)<br></br>#<br></br># bin/<br></br>$ git commit -m "WIP. new feature"<br></br>[newFeature eea0ced] WIP. new feature<br></br> 4 files changed, 137 insertions(+), 13 deletions(-)<br></br> create mode 100644 src/es/udc/cartolab/gvsig/tocextra/preferences/TOCExtraPreferencesPage.java<br></br>

Subimos al repositorio la refactorización

<br></br>$ git checkout master<br></br>$ git pull --rebase<br></br>$ git checkout refactor<br></br>$ git rebase master<br></br>$ git checkout master<br></br>$ git merge refactor<br></br>$ git push<br></br>$ git branch -D refactor<br></br>$ git checkout newFeature # para seguir trabajando<br></br>
Parece complicado, pero en realidad es más difícil de leer que de escribir una vez coges un poco de costumbre.