jueves, 29 de enero de 2015

Contar frecuencia de palabras en un texto (versión 2) sin distinguir mayúsculas de minúsculas

Como complemento a la publicación de hace unos días, en la que contaba cómo contar cuántas veces aparece cada palabra en un fichero de texto, aquí podemos ver otra versión en la que se utilizan las "clases" (categorías de caracteres) definidas en el comando "tr", cuyos nombres son bastante intuitivos.  

Fig. 1. A ver quién tiene redaños a contar las palabras en este texto,
un evangelio alemán del s. XV

No es una mejora espectacular respecto a la opción de especificar los caracteres por rangos o individualmente (aquí sí es significativa la mejora), pero al menos así uno está seguro de que no se deja fuera un signo de puntuación si establece la categoría :punct:, por poner un ejemplo.

El código:

cat palabras.txt | tr [:punct:][:blank:][:digit:] "\n" | tr [:upper:] [:lower:] | sort | uniq -c | sort -nr > resul.txt

Una mejora añadida a esta versión es que no distingue entre mayúsculas y minúsculas, lo que he conseguido con la segunda invocación al comando "tr" que, como se puede ver, transforma todas las mayúsculas ([:upper:]) en minúsculas ([:lower:]).

Las categorías admisibles en el comando "tr" son (al menos en la versión de tr que tengo en mi máquina Windows actual):

 Fig. 2. Clases (categorías) de caracteres en el comando tr


Aquí está el enlace a la versión anterior, donde está explicado un poco más detallado el código
http://cosicasdeinformatica.blogspot.com.es/2015/01/contar-frecuencia-de-palabras-en-un.html

lunes, 5 de enero de 2015

Contar frecuencia de palabras en un texto con los filtros (comandos de consola) de Linux


Esta es una de esas necesidades recurrentes que aparecen cada poco tiempo. Y al final, siempre termino buscándolo en Internet, así que me he decidido a ponerlo aquí simplemente para tenerlo a mano.


El caso es que tengo un documento del que me gustaría sacar la estadística de palabras más utilizadas. O ya puestos, no limitarme a las más utilizadas, sino contar el número de veces que aparece cada palabra, para todas ellas.

Hay muchas soluciones para esto, podéis, por ejemplo, mirar aquí, en StackOverflow [1] varias formas de hacerlo.

La que a mí me ha parecido más sencilla, dentro de lo que yo necesitaba, y con alguna adaptación por mi parte (la opción -r en el sort) es esta:


Figura 1. Las 20 palabras más utilizadas en un texto



ALGUNOS DETALLES


¿Y si quiero saber las menos utilizadas? Simplemente, miremos el final del fichero:


Figura 2. Las palabras menos utilizadas (una vez) están al final


Al mirar el fichero de resultados, me he dado cuenta de que me incluye los dígitos. Puede ser que alguien quiera contar el número de veces que se menciona un año, por poner un ejemplo en el que interese contar los números, pero no es mi caso, así que me gustaría descartar los dígitos.

Por otro lado, me gustaría también, una vez puesto, ignorar los signos de puntuación como el punto, la coma, el punto y coma, paréntesis, comillas dobles, etc... Solucionar esto es fácil.

Habréis visto que el espacio en blanco es el único separador de palabras que estoy utilizando, así que lo único que tengo que hacer es decirle al comando tr (translate, traducir unos caracteres en otros) que no sólo me "traduzca" los espacios en blanco a nueva línea, sino también todos los caracteres que quiero excluir. Algo así:

Figura 3. ¿Y si quitamos los dígitos y signos de puntuación?

Hmmm... vaya. En la primera línea vemos que aparece una "palabra" que es el espacio en blanco. Bueno, no era mi intención contarlo, pero esto tampoco es un problema, se puede ignorar. Por otro lado, vemos que la palabra "de" ahora se cuenta algunas veces más (ha pasado de 1709 a 1712 apariciones). Seguramente antes había algunas apariciones en la que estaba pegada a una coma o algún otro signo de puntuación. Lo mismo ocurre con "la", "que" y otras palabras. Parece que eso pinta bien.

Pero si vemos las últimas líneas, aún siguen apareciendo dígitos. ¿Qué ha pasado? Y, por cierto, el símbolo del % y el € y "las otras" comillas dobles también los quitaré en la próxima versión de mi script.

Lo que ocurre con los dígitos es que le he querido decir que traduzca cualquier cosa que esté en el intervalo 0..9 en un carácter de nueva línea. Y yo, ignorante, he pensado que el intervalo para definir un dígito se podía poner como para otros filtros de unix, como un rango. Pues resulta que no, para el filtro tr podemos usar ciertas categorías de caracteres especiales como :digit: :alpha: y otras (más info tecleando "man tr").

Así que la forma correcta de decírselo sería utilizar esta categoría o simplemente teclear directamente los diez dígitos en la orden:
 
Figura 4.Ahora sí

Como veréis, he introducido algunos caracteres especiales (como tres versiones para las comillas dobles, pues el texto provenía de un documento de Writer de LibreOffice y tenía comillas normales y tipográficas, que a su vez diferencian entre las de apertura y las de cierre), o los tres puntos suspensivos como un único carácter. Como estos caracteres no he sabido cómo ponerlos directamente con el teclado, he usado el copiar / pegar de la consola para conseguir introducirlos en la línea del script.

Por último, os pego aquí la línea final del script en modo texto para que podáis copiarla si os interesa:

cat texto.txt  | tr ' .,;:0123456789()[]"“”%€…' '\n' | sort | uniq -c | sort -nr > resul.txt


Quedan un par de cosas pendientes, como las dichosas tildes, pero eso ya os lo dejo a vosotros, que no es cuestión de darlo todo masticado.

Creo que esto es un buen ejemplo de la potencia de los filtros en el mundo *NIX, y de cómo combinar herramientas pequeñas que hacen pequeñas tareas de forma muy eficiente, para conseguir resultados combinados verdaderamente potentes (¿alguien ha dicho sinergia?).


REFERENCIAS

[1] Contar palabras de diferentes maneras. http://stackoverflow.com/questions/10552803/how-to-create-a-frequency-list-of-every-word-in-a-file

miércoles, 3 de diciembre de 2014

Convertir columna NULL en columna NOT NULL


1. EL PROBLEMA

Parece una tontería (y en el fondo, lo es), pero esta mañana me he enfrentado a la necesidad de tener que cambiar el diseño de una tabla para especificar la restricción sobre una columna, que inicialmente podía contener valores nulos, para que fuera una columna NOT NULL. Coser y cantar, me he dicho... Pero no. La cosa se ha complicado un poco.

Figura 1. Situación de partida: actualmente la columna id_concurso puede ser NULL. Queremos cambiar esto

Antes de nada, habrá que rellenar de datos esta columna, para asegurarnos de que no hay ningún registro con NULL en ese campo. Esto es de cajón (no puedo indicar que sea NOT NULL una columna que contiene datos NULL), así que asumimos que esto ya lo hemos hecho (por ejemplo, se pueden actualizar todos los NULL a un valor especial como cero o un número negativo).


2. PRIMER INTENTO: EL DISEÑADOR GRÁFICO DE TABLAS

Como la base de datos está en una instancia de SQL Server, en primer lugar, he intentado hacer el cambio desde la interfaz gráfica del SQL Server 2008 Management Studio, la herramienta oficial de administración de bases de datos de Microsoft, asumiendo que la cosa iba a ser cosa de desmarcar el checkbox y guardar.

Figura 2. Desmarcar el checkbox de "Permitir valores NULL" y ya está. ¿O no?

Pero... cuando lo he intentado, ¡mi gozo en un pozo!

Figura 3. Mensaje de error. No se puede hacer desde la interfaz gráfica. ¡OMG!


3. SEGUNDO INTENTO: DDL

Bueno. No es la primera vez que esta herramienta, el Management Studio, me da estos disgustos. A veces impide hacer cosas desde la interfaz gráfica (como alterar la PRIMARY KEY) pero me permite hacerlas escribiendo la correspondiente instrucción DDL en una ventana de consulta. Así que intentaré hacerlo así.

Después de intentar recordar (sin éxito, mi memoria no da para mucho) la sintaxis de la instrucción ALTER TABLE para hacer esto, me he tenido que lanzar a una búsqueda en Internet, asumiendo que lo iba a encontrar en menos de un minuto. Pero...

... buscando... buscando... buscando...

...tras unos minutos dando vueltas, me encuentro con que aparentemente NO se puede hacer en un único paso (ah, quizás mi memoria no era tan mala después de todo). Aquí tenéis una explicación (en inglés) de cómo se puede hacer para Firebird, pero imagino que el proceso puede valer para cualquier otro motor de BD. Básicamente, los pasos son:

1. Crear una nueva columna NOT NULL
2. Rellenar de datos esta columna con los datos de la columna original
3. Eliminar la columna original
4. Renombrar la columna nueva con el nombre de la columna original

OJO: si lo miráis en el ejemplo de Firebird que os he enlazado, la sintaxis que allí aparece no es válida para SQL Server (no sé si es que con Firebird vale, o es que directamente han cometido algún error sintáctico).

Se entiende, ¿no?

Ok, manos a la obra.


Paso 1. Crear nueva columna temporal

Al ejecutar la primera instrucción, obtengo el mensaje de error siguiente:

Figura 4. Mensaje de error. No puedo crear una columna NOT NULL. 

Claro, qué despiste. Si crea una columna nueva NOT NULL, ¿qué valores le asignaríamos a los registros existentes en esa columna? Así que tendremos que especificar un valor DEFAULT para esos registros, dejando la instrucción así (esto no lo tuvieron en cuenta en el ejemplo del Firebird)

1. ALTER TABLE mitabla ADD columna_nueva INTEGER NOT NULL DEFAULT 0


Figura 5. Ahora sí: nueva columna no nula creada. Datos por defecto a 0 (cero)


Paso 2. Rellenar los datos

Figura 6. Actualizar el nuevo campo a partir del antiguo. Sin problemas


Paso 3. Eliminar la columna original

Figura 7. Eliminar columna


Paso 4. Renombrar la columna

Figura 8. Vaya, la sintaxis en SQL Server no es 'RENAME COLUMN'.

Un par de consultas al patito y veo que en SQL Server, para renombrar una columna de una tabla, hay que usar el procedimiento sp_rename,

Figura 9. Renombrar una columna con sp_rename. ¿Por qué no me funciona?

Bueno, como veréis en la figura 9, no me ha funcionado, seguramente por algún error de sintaxis. Me he vuelto loco probando distintas maneras: con comillas sencillas, con comillas dobles, con el nombre simple de la tabla, con el nombre de la tabla totalmente cualificado (precedido de esquema y propietario)... y no he conseguido ejecutar el sp_rename. Lo que sí he comprobado es que con el diseñador, en la interfaz gráfica, sí que te deja modificar el nombre de la columna, así que he optado por esa opción, la fácil. Pero agradecería si alguien me sabe decir por qué no me ha funcionado ninguna de las opciones anteriores.

Figura 10. Podemos renombrar la columna desde la vista Diseño de la tabla


4. CONCLUSIÓN

Aunque en principio parece una operación trivial modificar el estatus de una columna de una tabla que acepta valores nulos a la situación en que no los acepta, a la hora de la verdad la cosa se puede complicar un poco.

Como resumen, aquí están los pasos que yo he dado en SQL Server 2008 Management Studio

1. ALTER TABLE mitabla ADD columna_nueva INTEGER NOT NULL DEFAULT 0;
2. UPDATE mitabla SET columna_nueva = columna_original
3. ALTER TABLE mitabla DROP COLUMN columna_original
4. Renombrar 'columna_nueva' a 'columna_original' en el diseñador gráfico

En la explicación en inglés que os he puesto arriba introducen un COMMIT entre los pasos 1 y 2 y otro entre los pasos 2 y 3. Me parece una muy buena idea, aunque os dejo a vosotros el pensar por qué.


EPILOGO

Después de tener esta entrada escrita, encuentro (concretamente, aquí) que hay una forma muuuuuuuucho más simple de hacer lo que yo quería

ALTER TABLE dbo.mitabla ALTER COLUMN columna_original INTEGER NOT NULL

La he probado y funciona perfectamente

Figura 11. ¡Haber empezado por ahí, hombre!


A la vista del resultado, a punto he estado de borrar esta entrada, pero no lo he hecho por varias razones

1) Ilustra un proceso que ocurre muchas veces en informática. Uno se plantea una forma de hacer las cosas, y cuando está cerca del final, descubre otra forma más sencilla de hacerlo. Mi opinión es que no hay que ser nostálgico, no te aferres a "tu" código por el hecho de que tú lo has "parido". Si hay una forma mejor, o más sencilla, tira lo viejo y quédate con lo mejor.

2) En el ejemplo del Firebird que encontré, se indicaba que con ese motor de BD había que hacerlo así, con la secuencia de cuatro pasos que os he puesto arriba. No he probado si también allí funciona la forma "simple", pero si no funciona, habría que usar la "compleja". Lo mismo vale para otros SGBD (Sistemas Gestores de Bases de Datos, o motores).

3) La secuencia de cuatro pasos indicada tiene sentido desde el punto de vista pedagógico, para aquellas personas que están aprendiendo temas de administración de bases de datos.

4) Como digo a veces, el lema de este blog es "Lo explico para enterarme yo". Es decir, si no me hubiera planteado explicar el problema paso a paso, quizás no hubiera encontrado la solución simple. Al menos, queda aquí para mí como una lección aprendida.

5) Y además, ya que la tenía escrita no iba a borrarla, ¿verdad? ;-) (esto es una broma, como digo en el punto 1: "no te aferres, no te aferres...").

viernes, 31 de octubre de 2014

Cómo saber cuánto tiempo lleva encendido el ordenador

A veces queremos saber cuánto tiempo lleva encendido un ordenador. ¿Cómo podemos hacer esto?


Figura 1. ¿Qué hora es en este reloj hebreo? (Visto en Praga)

1. Respuesta corta

En Linux, MacOs, HP-UX y versiones varias de UNIX: comandos "w", "uptime" y "top"

En Windows: comando "systeminfo"


2. Respuesta larga

2.1 Aplicaciones
Simplemente, queremos saber cuánto lleva encendido el equipo. O bien, somos los responsables de un servidor, y queremos saber si el servidor se ha reiniciado por la noche, por ejemplo. O hemos llegado a casa y hemos pillado a nuestro hijo todo viciado matando orcos a diesto y siniesto. A pesar de que le dijimos que sólo podía jugar una hora al día, tiene los ojos inyectados en sangre, rojos como dos tomates, sospechamos algo y no nos creemos lo que nos jura y perjura de que acaba de encenderlo "hace ná". Queremos comprobar, en todos estos casos, cuánto tiempo lleva el ordenador encendido.

2.2 En Linux
Si el equipo está ejecutando un Linux, bastará con teclear bien poco, una sola letra y hecho. El comando "w" nos da la información que queremos en la primera línea de su salida. Como una imagen vale más que mil palabras, ahí va un ejemplo:

Figura 2. Este equipo lleva 4 días, 4 horas y 14 minutos encendido

Tenemos más información adicional en ese comando, pero la que nos interesa está en la primera línea, junto con los datos de carga del procesador en el último minuto, últimos 5 y últimos 15 minutos. Si lo único que queremos es la información de esa primera línea sin mostrar la otra información (la de los usuarios que hay conectados), entonces podemos hacer un grep para solo mostrar la primera línea, así:

$ w | grep "load average"

(ojo, esto podría sacar también otras líneas que contuvieran esa cadena de texto)

O bien, y mejor aún, ejecutar el comando "uptime", que muestra únicamente esa primera línea.

Figura 3. Uptime como un "w" limitado a la primera línea

Otro comando que está en todos los *NIX modernos y que da esta misma info (más un montón de información adicional) es el comando top. Así, si ejecutamos

$ top

Obtendremos algo así

Figura 4. El comando "top" también nos dice cuánto tiempo lleva encendido el ordenador

Aunque a decir verdad, a mí me gusta más la versión de "top con colorines", llamada "htop" (también existen "atop" y otros...)


Figura 5. htop: top con maquillaje de colores

2.3 En Windows
En todas las versiones de Windows desde XP tenemos el comando "systeminfo", que se encarga de recoger un montón de información del equipo, entre ella la que nos interesa. En XP salen tantas líneas que se pierde la información por arriba, y en mi caso, el buffer de la ventana de comandos no conserva todas las líneas cuando vuelvo hacia atrás, así que he tenido que redirigir la salida al comando "less" para que me la muestre paginada

c:\> systeminfo | less

También podríamos haber redirigido esta salida a un fichero de texto y luego abrirlo con el bloc de notas.

Al ejecutar systeminfo, tras unos segundos, durante los cuales vemos unos mensajes indicando qué está haciendo el programa, tenemos una salida tal que así

Figura 6. Salida de "systeminfo" en Windows XP

donde podemos ver que el equipo lleva 4 días y casi 11 horas encendido (penúltima línea de la imagen).


2.4 Mi script personal
Como me gusta la salida en una única línea que proporciona el comando uptime de Linux, me he hecho mi pequeño script en Windows, lo he colocado en la carpeta de utilidades que tengo incluida en el PATH, para poder invocarlo igual que lo hago en Linux. Lo he llamado "uptime.cmd", y su contenido es sencillamente las siguientes dos líneas

Figura 7. Script para implementar un uptime

(el comando "find" es equivalente al grep de Linux)

Y ahora sí, en mi consola de Windows

Figura 8. Uptime disponible también en Windows

Y así no tengo que pensar si estoy en Linux o en Windows, en ambos sitios puedo escribir uptime y respuesta inmediata.

Y ahora pregunto yo...
Dicho todo esto, ¿alguien sabe cómo ver en un smartphone con Android el tiempo que lleva funcionando desde el último reinicio? Seguramente no sea muy complicado, pero le he dedicado unos minutos y no he hallado la respuesta rápidamente. Voy a seguir buscando.

Ahí queda la pregunta


lunes, 20 de octubre de 2014

Validación de documentos (X)HTML

Si recordáis la entrada de hace unos días (enlace abajo) hablaba del Principio de Robustez de Postel. Y decía que los navegadores suelen aplicarlo siendo muy transigentes con lo que aceptan como entrada en las páginas web. Aunque una página no se ajuste exactamente a la especificación HTML correspondiente, normalmente los navegadores hacen todo lo que pueden por mostrar una vista "razonable" de la página.

Pero que ellos sean permisivos no quiere decir que los desarrolladores nos debamos relajar. Tenemos que intentar que nuestras páginas sean lo más ajustadas posible a la especificación. Para ello, podemos usar los validadores proporcionados por el W3C u otras instituciones. Exigirnos a nosotros mismos hacer páginas estrictas se corresponde con la parte "be conservative" del principio (ver la entrada anterior, enlace abajo).

Para ello, podemos entrar en el validador del W3C, en la dirección http://validator.w3.org/, y ahí podemos poner la URL de una página web que queramos validar. Por ejemplo, vamos a probar la página principal de la CARM. Introducimos su URL y pulsamos "Check"

Y en este caso vemos que la página valida perfectamente respecto al esquema XHTML 1.0 Transitional. El validador del W3C ha accedido a la página que le hemos dicho y ha leído su contenido y lo ha contrastado con respecto a la especificación.



VALIDACIÓN LOCAL

Pero, ¿qué pasa si queremos validar una página local a la que el W3C no puede acceder, ya que no tiene acceso a nuestra intranet? Por ejemplo, una página principal del servidor web que tengo instalado en mi equipo para hacer pruebas. En este caso, el W3C nos dice que no puede acceder a esta página, por no ser pública


Esto también ocurre con algunas páginas que utilizan HTTPS en vez de HTTP.

Lo que sí podemos hacer es usar otra opción existente en el validador, bastante útil, y que consiste en pegar directamente el código HTML que queremos validar en un cuadro de texto. Para esto,

  1. Abrimos en un navegador la página web que queremos validar y mostramos su código fuente y lo copiamos al portapapeles. Para ver el código fuente de la página, en los principales navegadores hay que pulsar Ctrl + U. Si quieres hacerlo por menú, en Firefox está en Herramientas / Desarrollador web / Código fuente de la página, y en Chrome está en Herramientas / Ver código fuente.
  2. Pulsamos sobre la pestaña "Validate by Direct Input" y pegamos ahí el código de la página a validar
  3. Pulsamos Check



Espero que en vuestras páginas no salga el mensaje de error, y os diga que todo está chachi piruli (en mi caso no ha sido así, ¡glups!)


ICONOS DE VALIDACIÓN

Una vez validada nuestra página, "tenemos permiso" para poner un icono que indique que la página se ha validado con respecto a tal o cual esquema (HTML 4, XHTML 1, CSS 3...).




Esto sirve para informar a nuestros visitantes de que nos hemos tomado la molestia de intentar ser un poco exigentes con respecto a la sintaxis y gramática de nuestra página. No es todo lo que hay que hacer en una página, pero al menos es un paso en la dirección correcta. Yo me he encontrado muchas veces estos iconos de validación en páginas de ciertas organizaciones, como por ejemplo algunas páginas de la Universidad de Murcia, como el Portal único de acceso (aunque no en la página principal [!]).



Esto significa que en algún momento, el desarrollador correspondiente validó la página y el resultado fue positivo. Sin embargo, se ve que después han hecho algunos cambios en la página y se les ha olvidado volver a validarla, pues si pruebo a validarla por mí mismo obtengo este resultado



donde vemos que la página tiene algunos errores de validación.

Así que ya sabéis, si validáis vuestras páginas (sea por URL o por entrada directa, o subiendo un fichero, que también se puede hacer así), no olvidéis revalidarla cuando hagáis algunos cambios de importancia.

Otra cosa importante: si la página a validar contiene datos personales (por ejemplo, una página con resultados de una BD), mi consejo es que no peguéis estos datos directamente en el validador, ya que de esa forma los datos personales estarían saliendo de vuestra organización y llegando (como mínimo) al W3C. No sé si el W3C registra una copia del código que valida, pero por si acaso lo hace, o por si hay alguien "in the middle" escuchando, no es una buena idea. Para esos casos, hay instrucciones en la web del validador sobre cómo se puede instalar una copia en un equipo local, donde podéis validar todas las páginas de datos que queráis. Si alguno lo prueba, estaré encantado de que nos deje aquí sus comentarios.


MI CASO

En mi caso, he validado algunas páginas realizadas por mí. Y sí, he encontrado errores. Cuando el listado de errores es un poco largo, por un momento te sientes como si fueras un chapucero. ¿Cómo es posible que mi página tenga tantos errores de validación? ¿Debo dejarme el desarrollo y dedicame a criar champiñones? Por suerte, esto es parecido a lo que ocurre con algunos compiladores de C, que a veces corregir el primer error hace que desaparezcan 20 ó 30 errores posteriores, y es que el validador a veces se hace un lío tras el primer contratiempo.

En cualquier caso, no hay nada mejor que conocerse. Así que me ha venido muy bien para conocer mi estilo propio de desarrollo (y corregirlo) el ver cómo la mayoría de mis errores se corresponden con los mismos cuatro o cinco errores recurrentes una y otra vez. Entre ellos, el no poner texto ALT en algunas etiquetas <IMG> (esto puede ser importante por accesibilidad, el atributo ALT es requerido), usar el cierre abreviado de etiquetas (ya sabéis, el />) en etiquetas que no lo admiten, o bien ignorar el atributo "type='text/javascript'" en algunos fragmentos de código JavaScript. Así que una vez corregidos estos pequeños errores, las páginas han validado correctamente y ya he podido poner el "sello" de página validada.

Se quedan en el tintero muchas cosas, como los diferentes esquemas contra los que validar nuestra página, validación de otras cosas que no son HTML, como por ejemplo el CSS, etc... pero eso lo dejo para quien quiera profundizar en el tema. No os lo voy a dar todo masticado, ¿verdad?

¿Y tú? ¿Validas tus páginas? ¿Contra qué esquemas? ¿Usas otro validador distinto del que proporciona el W3C (sí, hay otros)? ¿Has descubierto si metes mucho la pata en tus páginas?


ENTRADAS RELACIONADAS

Sé conservador, sé liberal...be water, my friend
http://cosicasdeinformatica.blogspot.com.es/2014/09/se-conservador-se-liberalbe-water-my.html


REFERENCIAS

¿De qué va todo eso de la validación? (en inglés)
http://validator.w3.org/docs/help.html#validation_basics

lunes, 29 de septiembre de 2014

Sé conservador, sé liberal...be water, my friend

Una vez conocí en la universidad a una chica extranjera que hablaba español bastante bien, aunque de vez en cuando tenía algún fallo. Le gustaba que le corrigiéramos sus fallos hasta en lo más insignificante. Si se enteraba de que le habíamos pasado un error sin corregir, nos presionaba para que la próxima vez no lo hiciéramos. Estaba empeñada en aprender hasta sus últimas consecuencias, aunque esto implicara hacer muchas interrupciones en la conversación.

- El bicicleta se me ha rrrroto
- Te puedo prestar la mía
- ¿"La mía"? ¿Bicicleta es un sustantivo femenino?
- Estooooo... sí
- ¡¡Y porrr qué no me lo has corrrregido??
- Bueno, te he entendido, no me pareció una cosa tan importante
- Sí lo essss. Te tengo dicho que no me pases ni uno
- De acuerdo. Se dice que "no me pases ni una"
- Grrrasssias
- Se dice "gracias"
- ¡Grrrmmppfff!

Sin saberlo, esta chica estaba aplicando en el ámbito de la filología una versión particular de la "Ley de Postel".

El Principio de Robustez

Jon Postel (Juanito para los amiguetes) fue un informático estadounidense, de los de la vieja escuela (nació en 1943 el buen hombre), que hizo muchas aportaciones a las tecnologías de Internet durante el nacimiento y los primeros años de la Red. Por algo lo llegaron a llamar "El Dios de Internet". Así, como suena, os lo aseguro. La verdad es que si vemos su foto, sí que se parece un poco a esa imagen un poco ñoña de dios como un viejecito con cara de buena persona con barba blanca (un amigo mío dice que le recuerda a David el Gnomo).

Fuente: Wikipedia, por el usuario Tedder
http://en.wikipedia.org/wiki/Jon_Postel#mediaviewer/File:Jon_Postel_sitting_in_office.jpg

Entre otras cosas, Postel fue el editor de numerosos documentos técnicos relacionados con estándares. Ya sabéis que los informáticos nos ponemos cachondos con las siglas, así que a estos documentos los llamaron RFC (Request For Comments). En concreto, el RFC 760 (si eres masoca, abajo tienes el enlace, aunque ya te aviso de que quedó obsoleto por documentos posteriores), especificaba lo relativo al protocolo TCP/IP, ya sabéis, una minucia sin importancia (con decir que prácticamente TODAS las comunicaciones en Internet se basan en él, ¡ahí es ná!). En ese RFC, Postel enunció, allá por enero de 1980, una frase famosa que pasó a la historia con su nombre. La "Ley de Postel" (o Principio de Robustez, que también se le llama así) viene a decir que "una implementación debería ser conservadora en lo que envía, y liberal al procesar lo que recibe" (traducción libre mía). También se ha enunciado a veces como "Sé liberal con lo que aceptas, sé conservador con lo que envías". Después de decir esta frase, Juanito se sentó con las manos cruzadas en su regazo, como lo véis en la foto.

En realidad, he mirado en el RFC 760 y este es el texto exacto del original en inglés (así podéis haceros vuestra propia traducción):

        3.2. Discussion

          The implementation of a protocol must be robust.  Each implementation
          must expect to interoperate with others created by different
          individuals.  While the goal of this specification is to be explicit
          about the protocol there is the possibility of differing
          interpretations.  In general, an implementation should be conservative
          in its sending behavior, and liberal in its receiving behavior
.  That
          is, it should be careful to send well-formed datagrams, but should
          accept any datagram that it can interpret (e.g., not object to
          technical errors where the meaning is still clear).


De acuerdo, pero... ¿qué significa esto? Pues básicamente, que cuando uno produzca datos de salida que vayan a ser procesados por otros, intentar que estos datos se ajusten al máximo a las normas, que se sea todo lo estricto posible. Pero, por el contrario, a la hora de recibir y procesar datos de entrada, aceptar estos aunque presenten algún defecto menor que no afecte a la posible interpretación (es decir, que no se descarten unos datos por un defecto "de forma", como se anulaban antes algunas multas). O dicho más llanamente, sé muy quisquilloso con lo que produces, y sé muy permisivo con lo que producen los demás.

O como dice mi amiga la Jenny, "me lo trago tó".


Un ejemplo

Por ejemplo, si estoy esperando un color en formato hexadecimal para el fondo de una página web, y el diseñador ha escrito algo como

bgcolor=#AABBCC

pues su intención está clara. Quiere pintar el fondo de la página de ese color tirando a grisáceo (desde luego, hijo, qué soso). Sin embargo, para cumplir con la especificación oficial, el color debería estar entrecomillado, ya sea con comillas simples o dobles, así

bgcolor='#AABBCC'

Un programa que se encuentre el color como en el primer caso, sin las comillas, puede hacer varias cosas. Una de ellas (si fuera quisquilloso con lo que recibe, que es LO CONTRARIO de lo que recomienda Postel) es dar un mensaje diciendo que la página no es correcta, informar de ello y no mostrar la página. Vaya, qué programa tan exigente, ¿verdad?

Un programa más "enrollao", al leer la primera línea, entiende lo que se quiere decir, aunque falten las comillas. Si aplica la ley de Postel, ese programa debería interpretar el color como si el usuario hubiera introducido bien los datos, con el color entrecomillado. Como dice Postel, "...no poner objeciones a errores técnicos si el significado está claro". O sea, vale, no me has puesto las comillas en el color, pero entiendo lo que quieres decir. Pelillos a la mar. Esto sería un ejemplo del "be liberal".

Por otro lado, si ese mismo programa se encarga de generar o enviar datos, debe obligarse a sí mismo a cumplir estrictamente con el estándar, y enviar el código del color con las comillas correspondientes, incluso en el hipotético caso de que supiera que el receptor es capaz de "digerir" los datos sin comillas. Eso no valdría como excusa. Aquí quien manda es la especificación, y nunca se sabe si en una próxima actualización del programa receptor el programador encargado de la misma va a seguir manteniendo el criterio del primer equipo de desarrollo o va a reprogramar la parte encargada de procesar los colores, y entonces puede que algo que haya estando funcionando hasta el momento, de pronto deje de funcionar. Por ello, más vale forzarse uno a generar datos "buenos". Nivel de autoexigencia alto. No nos vamos a detener por unas comillas, ¿verdad? ¿Qué somos, leones o huevones?

Algunos de los mejores ejemplos de programas conservadores-liberales en este sentido lo tenemos en los navegadores más famosos. La mayoría de ellos son capaces de leer una página HTML y, aunque no esté bien formada, puede visualizarla haciendo algunas suposiciones razonables cuando se encuentre errores menores. Hay que tener cuidado, ya que puede que nos navegadores diferentes hagan diferentes suposiciones "razonables" (este concepto a veces es taaaaaan ambiguo...). De hecho, quizás os haya pasado a veces que hayáis comprobado que una página web se visualiza de forma ligeramente distinta en un navegador u otro, ¿verdad? Diferentes mentes, diferentes suposiciones "razonables".

También hay quien advierte de que una aplicación demasiado "tragona" puede poner en riesgo la seguridad precisamente por ese afán por aceptar datos que no sigan los patrones exactos que se esperan de ellos. Algo que también hay que tener en cuenta.

En fin, como resumen, que la ley de Postel viene a ser como una ley del embudo, pero al revés: lo ancho para los demás, lo estrecho para mis programas.

Un aparte


Además, la Ley de Postel es una buena receta para otras facetas de la vida. ¿Os imagináis cómo funcionaría la Sociedad, por ejemplo, si todos fuéramos un poco más transigentes con lo que esperamos de los demás, y fuéramos más estrictos con lo que le damos nosotros al mundo? Normalmente, solemos funcionar al revés.

La estudiante de la que os hablaba al principio es otro buen ejemplo de la parte "be conservative": se exigía hablar perfectamente bien, aunque sabía que podía defenderse y hacerse entender con soltura hablando regular. Pero no, ella tenía un nivel alto de autoexigencia. Be conservative.

Bueno, todo esto lo decía como introducción para hablar sobre el tema de la validación de documentos HTML, pero como esta entrada me está quedando ya un poco larga, hablaré de ello en otra ocasión.

Que ustedes lo codifiquen bien (y conservadoramente ;-)

Y rezadle a Postel.



Referencias

El principio de Robustez, explicado un poco más en detalle
En inglés: http://en.wikipedia.org/wiki/Robustness_principle

El RFC 760, donde se enunció por primera vez este principio
http://tools.ietf.org/html/rfc760

martes, 26 de agosto de 2014

Fotos públicas en Endomondo

Desde principios de año tenía por ahí aparcado y pendiente este tema del que voy a hablar hoy. Hace unas semanas, Chema Alonso publicó esta entrada hablando acerca de algunos problemas de privacidad en Endomondo (lectura muy recomendada), así que me he decidido a publicar lo que yo había experimentado, que viene a ser un dato más que añadir a lo que él cuenta allí. Como dicen los abogados: "...a mayor abundamiento..."

El caso es que cuando salgo a correr o a pedalear, suelo utilizar la aplicación Endomondo para registrar mis "proezas". Me gusta esta aplicación, ya que luego puedo entrar en la página web y revisar mis prácticas, exportar el fichero GPX con la ruta, ver estadísticas, etc...



Una de mis "proezas". Como véis, estoy hecho un espartano (¡aug!).

Pues bien, me encontraba yo revisando mis prácticas en el navegador cuando se me ocurrió hacer clic en mi imagen de perfil. Esto hizo que se me abriera una ventana aparte con la imagen



Sí, es la misma foto que tengo en mi perfil de Google+, y en varios sitios más. Original que es uno

Hmmm... Supongo que ya os habréis dado cuenta, ¿no? Aquí hay algo que pinta raro. ¿Las imágenes tienen una URL fija? No se accede a ellas a través de un script que valide la sesión del usuario. A ver, voy a cambiar algún dígito de la URL de mi foto de perfil, a ver qué sale...



Vaya, un vecino de URL

Parece ser que Endomondo no exige nada para que puedas ver la foto de perfil más allá de saberte la URL. Siendo esto así, a cualquier novato con un conocimiento mínimo de programación no le costaría nada hacer un pequeño script que con wget se fuera descargando imágenes, una tras otra, "a ver qué sale". Sería más o menos algo como esto:


 1 #!/bin/bash
 2 
 3 desde=1
 4 hasta=100
 5 ruta1=http://image.endomondo.com/resources/gfx/picture/
 6 ruta2=/big.jpg
 7 
 8 i=$desde
 9 while [ $i -le $hasta ]; do
10     echo "descargando $ruta1$i$ruta2"
11     wget $ruta1$i$ruta2 -O big.$i.jpg
12     let i=$i+1
13 done 
14 
El script para Linux. La adaptación a Windows es fácil, pero quien la quiera tendrá que hacérsela 

Como se puede ver, he elegido un rango pequeño de perfiles, del 1 al 100, por poner un ejemplo, pero se podrían modificar estos límites a voluntad y explorar qué fotos hay por ahí. Muchas fotos de esos perfiles no existen, y muchas otras contienen elementos donde la privacidad no es relevante (¿por qué a tanta gente le gusta poner la foto de su bici de montaña?), pero hay otras donde se ve gente acompañada de otra gente, con sus niños, etc...

¿Es esto un problema? Pues depende. Depende, sobre todo, de los términos y condiciones que uno acepta cuando se registra en Endomondo. Así, a priori, antes de leerlos (enseguida los veremos), me parece que no es lo ideal. A mí me parece bien que mis amigos en Endomondo vean mi foto de perfil, pero no que la pueda ver todo el mundo, incluso aquellos que no están registrados en la web.

Si leemos detenidamente la política de privacidad, nos encontramos que nuestra foto de perfil forma parte de nuestros datos personales

Tu foto de perfil forma parte de tu información personal

Y un poco más adelante


vemos que nuestra foto de perfil es pública por defecto, y que CONSENTIMOS en que así sea si no cambiamos la privacidad en nuestra cuenta. Hmmm, no me parece la mejor opción, pero así son las cosas.

¿Puedo cambiar esto en la configuración de la privacidad de mi cuenta? Bueno, más o menos

Tu perfil, o lo ve todo el mundo o los usuarios de Endomondo

En casi todas las opciones (la mayoría de las cuales vienen por defecto con el valor "Todos") se te da la opción de poner "Amigos", para limitar la visibilidad de tus datos, o incluso puedes poner "Sólo yo". Sin embargo, para la opción de mi perfil sólo puedo elegir "Todos" o "Usuarios Endomondo". Vale, lo cambio para que sólo lo puedan ver los usuarios de Endomondo.

Y una vez cambiado, intento ver si tengo acceso a mi foto de perfil poniendo la URL del principio... y el resultado es... ¡se sigue viendo! (he de reconocer que no me sorprende, me lo esperaba).

Conclusión: que tu foto de perfil sigue siendo visible para TODO EL MUNDO, no sólo para los usuarios de Endomondo.

Otra cosa: no soy ningún experto en políticas de privacidad, pero ya que han hecho el esfuerzo de traducir la interfaz al idioma español, ¿no deberían haber hecho lo mismo con la política de privacidad?

Mi consejo: no subas a Endomondo fotos que te interese tener con verdadera privacidad, ya que están accesibles públicamente mientras Endomondo no cambie esto.

¿Y tú, también tienes subida a Endomondo esa foto que no te gusta que todo el mundo vea?

Enlaces relacionados

Endomondo: www.endomondo.com

Róbame que estoy haciendo deporte: http://www.elladodelmal.com/2014/07/robame-que-estoy-haciendo-deporte-y.html

viernes, 25 de julio de 2014

Habilitar las librerías de cifrado de PHP en Ubuntu

Para cifrar (encriptar no existe para la RAE, aunque muchas veces utilicemos ambos verbos como sinónimos) un bloque de datos, en PHP podemos utilizar la función mcrypt_encrypt

Fig. 1. Parámetros de mcrypt_encrypt

El primer parámetro de esta función hace referencia al algoritmo que emplearemos. Pero, ¿qué algoritmos podemos utilizar? Para ver los que hay disponibles en nuestro sistema, podemos utilizar la función mcrypt_list_algorithms. Por ejemplo, así:

 1 <?php
 2 echo "<pre>" . print_r (mcrypt_list_algorithms (), TRUE) . "</pre>";
 3 ?>
Listado 1. ¿Qué algoritmos puedo utilizar para cifrar mis datos?

He probado esto en Windows y la salida ha sido la siguiente:

Figura 2. ¡Hala, qué variedad para elegir! Pito, pito, gorgorito...

Pero, al probar lo mismo en Ubuntu, la salida ha sido...


...




¡absolutamente nada!


Pero... ¿qué está pasando?????


Fig. 2. WTF!!!!!?????

Vale. Tras un poco de surfeo web, parece ser que hay que hacer una receta de 3 pasos:

1) Instalar php5-mcrypt
2) Reiniciar el servidor web
3) Habilitar la extensión mcrypt

Si sabéis hacer esto, podéis dejar de leer ya. Si eres como yo, que no sabía cómo se hacía, aquí están los detalles:

1) Instalar php5-mcrypt

$ sudo apt-get install php5-mcrypt

Como podemos deducir del nombre, hemos de disponer de la versión 5 o superior de PHP. ¿Que cómo sabemos cuál tenemos? Pues así:

$ php -v

Si no tienes la 5 o superior, actualízala (si puedes).


2) Reiniciar Apache

Tienes varias formas. Por ejemplo, así

$ sudo /etc/init.d/apache2 restart

o bien

$ sudo service apache2 restart

Tras esto, aún seguimos sin poder obtener los algoritmos de cifrado ("cifradores" los llama la documentación oficial de PHP) disponibles.


3) Habilitar la extensión en el fichero php.ini

Para ello, se incluye la línea

extension = mcrypt.so

en el fichero de configuración de PHP, el famoso php.ini.

Y ahora ya... ¡sí! Al ejecutar en Ubuntu el script de antes (Listado 1) obtenemos la salida

Figura 3. La misma lista de "cifradores" que en Windows, aunque cambie el orden de algunos elementos

Hala, ya podéis darle un buen uso a las funciones de cifrado.

viernes, 18 de julio de 2014

Cuánto te mide, cariño (Un Programador Honesto e Inteligente [y guapo, sobre todo guapo]) - Parte 4 de 4

(continúa)

PARTE 4 DE 4 (¡POR FIN!)

¿Deberíamos contar las líneas en blanco en un programa como "líneas de código"? ¿Y los comentarios? A priori, todo parece indicar que no. Imaginemos que mi jefe mide mi productividad por el total bruto de líneas de código, incluyendo las líneas en blanco y los comentarios (por fortuna, un jefe que sabe lo que se hace no lo haría sólo así, es una medida muy chapucera). Entonces yo podría insertar deliberadamente líneas en blanco a troche y moche y comentarios innecesarios cada dos por tres con cualquier excusa, "para aumentar la legibilidad" (e intentar conservar mi trabajo hasta que detecten el "truco"). Esto da un argumento a favor de no contar las líneas en blanco ni los comentarios. Así, metas más o menos, da igual. Sólo cuenta el CÓDIGO DE VERDAD.

Sin embargo, es verdad que un par de líneas en blanco insertadas en lugares estratégicos pueden aumentar la legibilidad y comprensibilidad de una rutina, mientras que un código al que le falten esas líneas en blanco o unos comentarios puede ser bastante más difícil de comprender. Respecto a los comentarios, pasa tres cuartos de lo mismo. Bien usados, son un mecanismo útil. Mal usados (abusados, generalmente), son un problema: aumentan la cantidad de lectura, pueden quedar desfasados respecto al código... El debate es antiguo y ha dado (y dará) para ríos de tinta. McConnell lo plantea como una pequeña escenificación parodiando las obras de teatro griegas y los diálogos de Sócrates, en el capítulo 32 de Code Complete (punto 32.2 To Comment or Not To Comment). Es una lectura que os recomiendo, al menos está escrita de una manera "gracioseta".


Figura 1. Un libro sobre desarrollo de software + unos cuantos chistes malo-buenos

En cualquier caso, como decía en la entrada anterior, la utilidad o no de medir estas líneas en blanco y comentarios DEPENDE DEL OBJETIVO. En mi caso, quiero medir MIS proyectos. Es decir, YO soy el medidor y YO soy el padre de la criatura a medir. Por lo tanto, como no me quiero engañar a mí mismo, asumo que el programador que ha creado ese código, aparte de ser guapo a rabiar, tiene dos características importantes para conmigo: es honesto y es inteligente (hola, autoestima, ya sabía yo que no tardarías en salir).


Figura 2. Así se me pone la cara pensando si contar o no las líneas en blanco. Lo sé, me pongo un poco raro cuando pienso, y la Angelina me mira que me quiere comer 

1) Con lo de ser honesto, quiero decir que no va a insertar más líneas en blanco de las que suele insertar en su estilo normal de programación. Tampoco va a meter comentarios de relleno, más allá de los que suele meter habitualmente. Es decir, en los proyectos usa las líneas en blanco y los comentarios como elementos que también forman parte del programa, en su justa medida, como suele hacerlo habitualmente en el resto de los proyectos. Es decir, no va a engañar, ni (mucho menos), a engañarse.

2) Inteligente significa que no abusa de los comentarios, no mete paja... En fin, que los usa bien. Por lo tanto, unos buenos comentarios para mí tienen tanto valor como unas líneas de código. Aquí radica la clave de mi discurso. Para mí, esos comentarios útiles SON PRODUCTIVOS. Incluso esas líneas en blanco. Luego, si al sacar las métricas del proyecto no los tengo en cuenta, estoy descartando un producto de interés. Es verdad que esas líneas no son de interés para el compilador, pero sí son de interés para otro programador, o para mi YO del futuro cuando vuelva a leer ese trozo de código dentro de unos meses. Por lo tanto, esos comentarios (y líneas en blanco correctamente utilizadas) que mejoran la legibilidad y comprensibilidad del código, se deben contar. Aportan valor al código fuente.

Esto, además, tiene el efecto colateral de que simplifica mucho la tarea de contar las líneas de código de mi proyecto. Se limita a contar las líneas que tiene cada fichero de código. Hacer un pequeño programa para esto es trivial. Aunque esto es un efecto secundario, nunca el motivo principal para no excluir esas líneas en blanco y esos comentarios.

Bueno, creo que con esto ya me he explicado lo suficiente. Quizás me he enrollado un poco de más, pero necesitaba dejar esto claro para explicar mis siguientes entradas, en las que llevaré esto de las métricas a un caso práctico, y quería justificar un poco las decisiones tomadas.

Prometo que en la próxima entrada pondré código, que hace tiempo que no se ve por aquí y eso no puede ser.

---
Enlace a la parte 1
http://cosicasdeinformatica.blogspot.com.es/2014/07/cuanto-te-mide-carino-el-proyecto-se.html

Enlace a la parte 2
http://cosicasdeinformatica.blogspot.com.es/2014/07/cuanto-te-mide-carino-no-cuentes-lineas.html

Enlace a la parte 3
http://cosicasdeinformatica.blogspot.com.es/2014/07/cuanto-te-mide-carino-o-tanto-medir-pa.html

martes, 15 de julio de 2014

Cuánto te mide, cariño (o Tanto medir, pa qué) - Parte 3 de 4

(continúa)

PARTE 3 DE 4

Enlace a la parte 1
Enlace a la parte 2

En mi caso, creo que el número de líneas de código, aún con todos sus defectos asociados, es la métrica MÍNIMA IMPRESCINDIBLE que debería incluirse en todo conjunto de métricas de un proyecto. Esto no quiere decir que sea la única que haya que considerar, esta métrica deberá estar complementada y apoyada por algunas otras (tampoco muchas, repito lo de "pocas, pero buenas").

Pero si alguien me dice que no tiene ni idea de las líneas de código del proyecto en el que se está moviendo, algo va mal. Es como si un arquitecto me dijera que está trabajando en un puente y no sabe de cuántos metros es (claro está, redondeando, no le voy a exigir saberlo al milímetro). Yo mismo, en mis primeros años como programador profesional, muchas veces he trabajado en proyectos de los que luego no he sabido describir su tamaño con una medida objetiva. Y no, no me valen cosas como "un proyecto grande", "un proyecto mediano". Eso no me parece propio de un ingeniero. Como ingeniero, te pido que me des algún dato OBJETIVO del proyecto. El número de líneas de código será un dato muy básico, de utilidad muy limitada, pero es OBJETIVO. Todas las métricas han de ser objetivas.



¿Cuáles son mis objetivos al medir el tamaño de mi proyecto?

1. Conocer algún DATO OBJETIVO de él, que pueda ser medido por un tercero sin influencia de factores subjetivos. El número de líneas de código lo es. Da igual que lo mida yo o que lo mida un revisor externo. Otra cosa es que establezcamos condiciones que sean las mismas para todos: si cuentan las líneas de comentario, si cuentan las líneas en blanco, los tipos de archivos que consideraremos (código fuente, ficheros de configuración, páginas HTML estáticas...) y todos los demás detalles. Normalmente, estos dos tipos de líneas, las blancas y las de comentarios, no se suelen contar, aunque yo tengo un criterio diferente en algunos casos, pero de momento no me quiero ir por las ramas. Lo importante es que los criterios estén bien fijados; una vez hecho, la métrica es un valor objetivo.

2. Poder COMPARAR dos proyectos (o más). Al menos, dos proyectos realizados por el mismo programador. Ya he hablado anteriormente de que diferentes programadores significa diferentes estilos de programación, y el mismo programa puede cambiar de "tamaño" según las manos por las que pase. Pero si lo que quiero es comparar dos programas hechos por la misma persona, entonces sí que significa algo el número de líneas de código. O si quiero medir la productividad de un programador a lo largo del tiempo, sí tiene sentido comparar el número de líneas de código que ha producido en diferentes semanas.

3. GESTIONAR LA COMPLEJIDAD, intentando detectar, por ejemplo, variaciones bruscas en el tamaño del proyecto. O intentando reducir el tamaño cuando sea posible sin menoscabo de la funcionalidad (por ejemplo, por hacer una refactorización). Si un lunes extraigo una métrica del proyecto y veo que se mueve por las 50.000 líneas, y al lunes siguiente el proyecto ha pasado a 60.000 líneas, algo significa, ¿no? Habrá que entrar luego en detalles, pero al menos podemos tener un sistema automatizado que nos haga saltar un aviso para después ponernos a bucear en los pormenores del proyecto de manera más refinada. Otro ejemplo: si voy a acometer una fase de refactorización de mi proyecto, sí tiene sentido medir las líneas de código antes y después de la operación, para evaluar de alguna manera de qué nos ha valido (también tendrá otros beneficios aparte de reducir el número de líneas, claro, como una mejor organización del código, una mayor legibilidad, simplificación de uso, etc.).

Curiosamente, cuando he empezado a medir mis proyectos con estos tres únicos objetivos, resulta que después las métricas me han servido para otras cosas. Una vez que tienes datos objetivos, se te ocurren nuevas formas de dotarlos de significado y hacer cosas interesantes con ellos. Es lo que decía al principio: pocas métricas, pero explotándolas a tope.


--
Enlace a la parte 1
Enlace a la parte 2


Related Posts Plugin for WordPress, Blogger...