Diseñar webs y aplicaciones móviles rápido y fácil

WireframeA la hora de diseñar ventanas, webs, y aplicaciones para móviles, más de una vez he intentado usar alguna aplicación como mockingbird o Pencil Project. La primera, mockingbird, es una aplicación web a la que se puede acceder desde cualquier navegador y te permite diseñar varias páginas con distintos elementos. En cuanto a la segunda aplicación, Pencil Project, nació inicialmente como una extensión de Firefox, pero ya dispone de versión multiplataforma de escritorio. La verdad es que también va muy bien.

El inconveniente de estas dos aplicaciones, es que por alguna razón, al final siempre me resulta más sencillo coger papel y lápiz y hacer cuatro garabatos mal hechos que me ayudan a organizar mis ideas mejor. Supongo que la razón es que al no ser diseñador, lo mismo me da hacer un diseño churro en papel en 2 minutos, que un diseño churro en un programa con elementos bonitos, donde suelo tardar 3 o 4 veces más… porque al final te lias, te lias… y el tiempo pasa y pasa.

Sea como fuere, el otro día descubrí Wireframe.cc, y la verdad es que quedé bastante impresionado por el UI. Es supersencillo, arrastras el ratón y listo, ya tienes un elemento. Haces click en el tipo de elemento que quieres, y ya lo tienes… haces doble click sobre el elemento, y puedes cambiar atributos, etc…

Realmente, es la primera vez que siento que una aplicación de este tipo no me hace perder el tiempo.  Por lo que he visto, esta aplicación está comenzando, y le faltan varios aspectos que pulir y funcionalidades que añadir, y supongo que se irán añadiendo, pero desde luego para hacer un diseño rápido y sencillo me sobra ;)

Os recomiendo que les echeis un vistazo a las tres aplicaciones que os he comentado, todas tienen sus cosas buenas o malas, y supongo que como todo en la vida, depende de las necesidades y preferencias que uno tenga. Yo de momento me quedo con wireframe.cc

Oferta de trabajo: buscamos programador

 

Update:  Ya hemos cerrado el plazo para enviar solicitudes.

En mi empresa estamos buscando ingeniero desarrollador de software para mi equipo, lo que viene siendo un programador, pero de los buenos ;p

Los detalles de la oferta, así como los datos de contacto, los podeis encontrar en el siguiente enlace:

https://dl.dropbox.com/u/20600084/JobOffer_SDE-Aug2012.pdf

No es una oferta para un programador normal, es una oferta para alguien a quien le apasione programar. Alguien a quien le guste resolver problemas complejos y se sienta cómodo trabajando con proyectos grandes. Alguien con experiencia programando en C/C++, HTML/JS/CSS, Python, … y en lo que le echen. C/C++ hay que dominarlo, lo demás ya es más opcional… alguien que sepa esto se puede adaptar y aprender fácilmente. Tienes puntos extra si has programado en ensamblador y si tienes años demostrables en la industria. Buscamos a alguien autosuficiente, con ganas de hacer cosas nuevas y ganas de mantener productios viejos :p  …hombre, todo no va a ser bueno…

Lo malo es que habrá productos “viejos” y complejos que mantener, lo bueno es que también hay proyectos nuevos y siempre hay tiempo para innovar, mejorar los productos existentes y hacer  prototipos de nuevos productos ;)

La oferta es para trabajar en El Campello, Alicante (España). Si no eres de por la zona, pero te llama la atención la oferta, te diré que como cosas buenas, tienes alquiler de apartamentos a 2 minutos de la oficina, con vistas a la playa y al mar, te diré que el ambiente de trabajo es cojonudo, y te diré que la oficina es bastante amplia (también se ve el mar desde la oficina), tenemos cocina, y realizamos compras mensuales en el supermercado para tener un poco de todo para almorzar. El horario es de 8 horas y salvo contadas ocasiones, no se hacen horas extra, cuando se hacen, se suelen cambiar por días de vacaciones/horas de descanso. Hay 25 días de vacaciones al año, y salvo muy contadas excepciones puedes elegir las fechas a tu gusto. Sé que todo esto suena raro para España, por eso lo comento.

Desde mi punto de vista, el currículum sirve para descartar, pero no para contratar, así que si no tienes demasiada experiencia, pero te encanta programar, y tienes ganas de aprender, manda un e-mail, igual eres tú el candidato que buscamos. Habrá una o varias pruebas para contratar/descartar candidatos, y en las pruebas habrá que calentarse un poco la cabeza… y cómo no, tendrás que demostrar que tienes aptitudes para programar y resolver problemas programando.

Esta oferta de trabajo es una recomendación personal a los lectores del blog. A mi me gusta programar y me gusta mi trabajo, si no no gastaría el tiempo en escribir un post en un día de vacaciones. El trabajo mola y está bien pagado (estamos hablando siempre de Alicante, España). Las cosas que desarrolles afectarán luego a millones de personas, osea que haciendo las cosas bien, también es un trabajo gratificante.

Dicho esto, si conoces a alguien a quien le pueda intersar esta oferta, mándale el PDF.

Suerte!

Nota final: este artículo refleja mis opiniones y valoraciones personales, no los de la empresa

Nota 2: la foto es de David, un compañero de la oficina que me ha dejado poner su foto con la nueva cocina ;)

Hack Manso: Mejorar la velocidad de SQLite en Google App Engine SDK

Estaba tratando de inicializar una base de datos en local, con el Google App Engine SDK y me estaba volviendo loco.

Ni siquiera era factible usar –use_sqlite que introdujeron en la versión 1.3.3. La velocidad de los inserts a la base de datos iban superlentos, en plan, diez por segundo. Infumable.

Vale, vale, es el SDK, y el objetivo es desarrollar la aplicación y la velocidad no es lo más importante… pero si para insertar 1000 datos, tienen que pasar 10 minutos, pues mal vamos. Si me dijeras 1 millón, pues aún lo entendería minimamente… pero ¿1000 miseros inserts? ¿10 minutos? ¿estamos todos locos?

Así que, partiendo de que SQLite parece funcionar de puta madre, pues no me cuadraba… Mirando el FAQ de SQLite, me he encontrado con que la pregunta 19:

(19) INSERT is really slow – I can only do few dozen INSERTs per second

La respuesta es, SQLite puede hacer fácil 50.000 inserts/segundo peeeeeeeero para garantizar la integridad de los datos, se espera a que el disco confirme que los datos se han escrito bien, por si se va la luz, etc… Vamos, un cuello de botella enorme, cuando a mi los datos me dan un poco igual porque es un entorno de prueba, lo que quiero es que vayan rápido los inserts porque si no me muero del asco desarrollando.

En fin, que la solución que dan es usar “PRAGMA synchronous=OFF“. La única forma de usar ese pragma, es editar el SDK del Google App Engine, y ejecutar esa línea tras inicializar la base de datos.

Hay que editar el archivo:

google_appengine/google/appengine/datastore/datastore_sqlite_stub.py

Vamos al constructor “__init__”, y después de que inicialize la conexión a la base de datos “self.__connection = sqlite3.connect [...]” pues metemos la siguiente linea:

self.__connection.execute(‘PRAGMA synchronous=OFF’)

Y, afotunadamente, cambiando esta línea he pasado de 10 inserts por segundo a más de 100 inserts por segundo. Más de 10x más rápido cambiando sólo una linea.

Ahora ya puedo continuar con lo que estaba haciendo.

, , , , ,

Truco Manso: obtener una cadena hexadecimal aleatoria en python

Obtener una cadena de bytes aleatoria es una de esas cosas que hacen falta de vez en cuando.
La opción más sencilla en python es importar uuid y hacer la siguiente llamada:

uuid.uuid4().hex

Ale, con esa llamada ya tenemos 32 caracteres hexadecimales aleatorios (16 bytes aleatorios).

¿Sabes de algún otro método?

,

TrucoManso: Transformar el tiempo en formato 24h a formato 12h (Python)

Truco manso para transformar una cadena de tiempo en formato de 24h en formato de 12h (AM/PM)


def ampmformat (hhmmss):
  """
    This method converts time in 24h format to 12h format
    Example:   "00:32" is "12:32 AM"
               "13:33" is "01:33 PM"
  """
  ampm = hhmmss.split (":")
  if (len(ampm) == 0) or (len(ampm) > 3):
    return hhmmss

  # is AM? from [00:00, 12:00[
  hour = int(ampm[0]) % 24
  isam = (hour >= 0) and (hour < 12)

  # 00:32 should be 12:32 AM not 00:32
  if isam:
    ampm[0] = ('12' if (hour == 0) else "%02d" % (hour))
  else:
    ampm[0] = ('12' if (hour == 12) else "%02d" % (hour-12))

  return ':'.join (ampm) + (' AM' if isam else ' PM')

Y un ejemplo de uso:

ampmformat ("00:00:00") # devuelve "12:00:00 AM"
ampmformat ("12:00:00") # devuelve "12:00:00 PM"

ampmformat ("01:23:45") # devuelve "01:23:45 AM"
ampmformat ("13:23:45") # devuelve "01:23:45 PM"
ampmformat ("05:43:21") # devuelve "05:43:21 AM"
ampmformat ("17:43:21") # devuelve "05:43:21 PM"
    
ampmformat ("11:59:59") # devuelve "11:59:59 AM"
ampmformat ("23:59:59") # devuelve "11:59:59 PM"

, ,

Google App Engine SDK 1.4.0 released

Ya está disponible la versión 1.4.0 del SDK de Google App Engine.

Particularmente resaltaría 3 cosas de este release:

  • Los taskqueues ya forman parte del API oficial, han dejado de ser experimentales ;)
  • Han multiplicado por 20 los tiempos máximos de ejecución de las tareas cron y de las tareas del task queue de 30 segundos a 600 segundos (10 minutos). Esto es fantástico, aunque puede ser peligroso. Habrá que usarlo sabiamente ;)
  • El uso del Channel API ya está disponible para todo el mundo de forma oficial.

El Channel API me impresionó cuando le eché un vistazo por allá por Mayo. A continuación el video del Channel API. Es bastante técnico y sólo tiene sentido si programas en GAE o si por ejemplo quieres hacer un API para comunicación Comet entre cliente-servidor:

Enlaces:

, , ,

Truco Manso: Obtener la latitud/longitud a partir de una dirección

Para un proyecto que espero que pronto vea la luz, he estado investigando cómo determinar la localización geográfica de cualquier sitio. Esto es, determinar la latitud/longitud a partir de una frase en plan “Elche, Alicante, Spain”

A esto se le llama Geocoding y a poco que he buscado tanto Google como Yahoo tienen APIs REST que te permiten enchufar queries en un servidor (aunque con unos términos de uso limitados).

En el caso de Yahoo, hace falta darse de alta para que te den un appid y poder hacer los queries.

En el caso de Google, no es así, y preguntar la latitud y longitud de “Elche, Alicante, Spain” es tan fácil como:

http://maps.googleapis.com/maps/api/geocode/json?address=Elche,+Alicante,+Spain&sensor=false

Esto devuelve un churrasco en JSON (también lo puedes pedir en XML) y dentro de este churrasco, dice que la latitud/longitud es:
“lat”: 38.2671765,
“lng”: -0.6952196

También existe GeoNames, que es menos preciso, pero puede resultar interesante también (ver enlace más abajo).

Para más información:

, , , , ,

Soporte de unicode en Python: Frustraciones y Soluciones

Personalmente el soporte de unicode en Python anterior a Python 3, siendo finos, es una puta mierda. Casi prefiero el soporte que tiene PHP 5.x de unicode (cero patatero).

Sinceramente es para volverse loco, porque cosas que a priori van, luego petan, o realmente no petan, sólo petan cuando intentas mostrarlas por la consola haciendo print…

En fin, que tratando de solucionar mis frustraciones con python y el unicode, he encontrado el siguiente enlace:

Overcoming unicode frustrations in Python 2

El enlace anterior es lectura obligada para cualquiera que de vez en cuando le salte una excepción tipo UnicodeEncodeError, como:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 654: ordinal not in range(128)

Finalmente, mi esperanza es que en Python 3 todo esto se solucione, y a juzgar por lo que he ido leyendo parece que si… pero ¡habrá que ver para creer!

, , ,

Serializando datos nativos en Python

Resulta que para un proyecto en Python en el que estoy trabajando necesitaba serializar algunas estructuras. El tema es que únicamente hacía falta serializar tipos nativos como listas, diccionarios, cadenas, enteros, etc…

Lo que me hacía falta era:

  • representación compacta
  • serialización/deserialización rápida
  • legible / editable por un humano

Así que después de pensar un rato, he encontrado 3 posibles soluciones para serializar datos arbitrarios:

  • pickle/cPickle que serializa cualquier cosa, viene con python, pero no es legible/editable
  • simplejson que serializa en formato JSON (el resultado es legible y editable)
  • PyYAML que serializa en YAML (el resultado es legible y editable)

El siguiente paso era coger un buen montón de datos, y hacer tests para ver que tal funcionan los encoders/decoders en cada uno de esos módulos.

A continuación puedes ver los gráficos de los tiempos de encoding/decoding para dos conjuntos de datos empleando cada uno de los formatos anteriores:

Python Serialization Speed Test (Tiny Dataset)

Python Serialization Speed Test (Huge Dataset)

A parte de la velocidad, también me interesaba medir la longitud de las cadenas generadas (cuanto menos, mejor):

  • yaml   tiny = 32604  // huge = 912912
  • json   tiny = 31305 // huge = 876540
  • pickle-raw    tiny = 34504 // huge = 986531
  • pickle-highest   tiny = 37541 // huge = 1101480
Conclusión:

Como se puede ver en las gráficas, y en la tabla anterior, considero que JSON es el que me hace mejor papel. Codifica / decodifica ligeramente más despacio que pickle (un 4% más despacio) pero la cadena resultante es legible y editable y además ocupa menos espacio que picke y que yaml.

Todos los tests han sido realizados con Python 2.5

El código:

Finalmente, aquí dejo un fragmento de código usado para obtener los tiempos que aparecen en los gráficos anteriores:

    start = time.time()
    for i in range (0, 100):
      yaml.safe_load (yaml.safe_dump (data))
    self.write ("YAML TIME = %.2f\n" % (time.time() - start))
 
    start = time.time()
    for i in range (0, 100):
      JSONDecoder().decode (JSONEncoder().encode (data))
    self.write ("JSON TIME = %.2f\n" % (time.time() - start))
 
    start = time.time()
    for i in range (0, 100):
      pickle.loads (pickle.dumps (data, pickle.HIGHEST_PROTOCOL))
    self.write ("PICKLE TIME = %.2f\n" % (time.time() - start))
 
    start = time.time()
    for i in range (0, 100):
      pickle.loads (pickle.dumps (data, 0))
    self.write ("PICKLE-RAW TIME = %.2f\n" % (time.time() - start))

, , , , ,

bbcodeutils: BBCode parser and BBCode to HTML for Python

Ayer anduve buscando algún módulo para Python para parsear Bulletin Board Code (bbcode para los amigos) o que fuera capaz de transformarlo en HTML.

Como ninguna solución cumplía mis necesidades al 100% he creado bbcodeutils que no es mas que un conjunto de clases en Python para parsear, generar y transformar bbcode. He intentado que sea lo más simple de usar posible.

Dentro de bbcodeutils encontrarás estas clases:

  • bbcodeparser: permite parsear y corregir código bbcode
  • bbcode2html: permite generar HTML a partir de un código BBCode parseado
  • bbcodebuilder: permite generar BBCode a partir de sentencias en Python

Aquí teneis el enlace para descargar bbcodeutils v1.0. Puedes usar este módulo libremente (ver readme.txt para más detalles).

A continuación voy a poner algunos ejemplos de uso de las operaciones más típicas.

Ejemplos:

En los siguientes ejemplos se asume que habrás hecho algo para cargar los módulos, en plan:

from bbcodeutils import bbcodebuilder, bbcodeparser
Parsear cadenas bbcode

Parsear una cadena BBCode se puede hacer de dos maneras, usando el constructor, o invocando a parse:

> bbcode = bbcodeparser('[b]bold string[/b]')

o bien:

> bbcode = bbcodeparser()
> bbcode.parse ('[b]first string[/b]')

Esto tampoco tiene más utilidad que la de ilustrar como parsear una cadena, pero al final uno lo que querrá será bien corregir el código BBCode, o bien producir HTML válido a partir de la cadena parseada

Corregir una cadena BBCode invalida

Para corregir una cadena BBCode mal formada, símplemente habría que parsear la cadena en cuestión y llamar al método bbcode que construye la cadena de nuevo, o bien transformar el objeto a cadena.

> bbcode = bbcodeparser("This is [b]bold and [i]this bold and italics[/b].[/color]")
> bbcode.bbcode()
"This is [b]bold and [i]this bold and italics[/i][/b]."
 
> str(bbcode)
"This is [b]bold and [i]this bold and italics[/i][/b]."

Nótese como se elimina el tag [/color] y se añade el tag [/i] que faltaba.

Transformar una cadena BBCode en HTML

La clase bbcodeparser implementa el método html que transforma el código parseado
en HTML válido.

> bbcode = bbcodeparser('[b]bold string[/b]')
> bbcode.html()
"<b>bold string</b>"
Generar código BBCode
> bbcode = bbcodebuilder()
> bbcode.b('string in bold')
"[b]string in bold[/b]"
 
> bbcode.url('http://www.codigomanso.com/')
"[url]http://www.codigomanso.com/[/url]"
 
> bbcode.url('Welcome to Codigo Manso', 'http://www.codigomanso.com/')
"[url=http://www.codigomanso.com/]Welcome to Codigo Manso[/url]"
 
> bbcode.list('item 1', 'item 2')
"[list]
   [*]item 1
   [*]item 2
[/list]"
Operaciones típicas en una linea de código

Corregir cadenas inválidas en una linea:

> str(bbcodeparser("[color=red]Fix this [b]string"))
"[color=red]Fix this [b]string[/b][/color]"

Transformar bbcode a HTML en una linea:

> str(bbcodeparser("[color=red]Fix this [b]string"))
'<span style="color: red;">Fix this <b>string</b></span>'

Ale, ¡Ya está!

Si alguien se anima a usar este módulo y quiere algún ejemplo más, o tiene alguna duda sobre su utilización, le animo a que deje un comentario en este post.

Enlaces de interés:

, , ,

prev posts