Mostrando entradas con la etiqueta desarrollo web. Mostrar todas las entradas
Mostrando entradas con la etiqueta desarrollo web. Mostrar todas las entradas

lunes, 12 de octubre de 2015

Desempolvando Django (4)

Hasta ahora hemos desarrollado algo muy básico: un listado de marcadores. Casi todo lo que hemos hecho ha sido definir y configurar cosas.

Veamos los siguientes pasos:

  • Cada marcador podía llevar asociada una imagen, mostrémosla en el listado

  • Debemos asociar una hoja de estilo a nuestras páginas

  • Debemos añadir alguna forma de crear nuevos marcadores y editar los existentes

  • Hay que preparar la aplicación para ser servida en un entorno "de producción", no desde el servidor de desarrollo

  • Y muchas más características y mejoras, por supuesto, pero vamos poco a poco


Mostrando la imagen en el listado


Recordemos cómo era nuestro modelo de datos (models.py):
from django.db import models

class Marcador(models.Model):
    titulo = models.CharField(max_length=200)
    url = models.CharField(max_length=500)
    descripcion = models.CharField(max_length=500)
    image = models.ImageField(upload_to='savebookmarks')

    def __str__(self):
        return self.titulo + ' (' + self.url + ')'

Al definir el atributo imagen especificamos la ruta donde se subirán las imágenes, es relativa al parámetro MEDIA_ROOT de settings.py

Si hemos creado unos cuantos objetos desde el "/admin", podremos mostrar su imagen en el listado. Para ello, en desarrollo, definiremos en settings.py una ruta más para ser servida como recurso estático. Esto "en producción" habrá que cambiarlo, pero por ahora seguimos con ello así:

En settings.py
STATIC_URL = '/static/'
MEDIA_ROOT = BASE_DIR + '/media'
STATICFILES_DIRS = (BASE_DIR + '/savebookmarks', MEDIA_ROOT)

STATIC se refiere a cómo se sirven recursos estáticos (hojas de estilo, JS, iconos, etc). MEDIA_ se refiere a cómo se sirven ficheros subidos por los usuarios. Por seguridad, en producción, separaremos totalmente ambos tipos de recursos. En desarrollo, los servimos igualmente con la app 'django.contrib.staticfiles' mediante la definición STATICFILES_DIRS.

En la template, incorporamos la imagen (marcador_list.html):
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'savebookmarks/estilo.css' %}" />

<h2>Marcadores</h2>
<ul>
    {% for m in object_list %}
        <li>
            <img src="{% static m.image %}" width="40" />
            <a target="_blank" href="{{m.url}}">{{ m.titulo }}</a>
            | (<a href="{% url "editMarcador" m.id %}">Editar</a>)
        </li>

    {% endfor %}
</ul>

<p><a href="{% url "addMarcador" %}">Añadir otro</a></p>

El tag {% static %} es atendido por la app 'django.contrib.staticfiles' y nos proporciona la URL relativa para ser servida por el servidor de desarrollo. En producción habrá que revisar esto. El resto de código lo revisaremos a continuación.

Enlazando una hoja de estilos


directorios

Como definimos en settings.py un
STATIC_URL = '/static/'

ahora podemos poner bajo esta URL nuestras hojas de estilo. El árbol de directorios del proyecto se va pareciendo a la figura.

La app 'django.contrib.staticfiles' encontrará los ficheros bajo static/ y los servirá adecuadamente.

Para enlazar estos ficheros, usamos el tag {% static %}, como se ha mostrado en la template.

En el paso a producción lo que se hace es utilizar un servidor web independiente para servir los recursos, en la documentación de Django se explica cómo hacerlo, por ahora mantenemos esta configuración en desarrollo.

Crear y editar marcadores


En este punto, utilizaremos el sistema de formularios de Django, que está muy bien pensado.

 

 

 

miércoles, 11 de marzo de 2015

10 años de desarrollo web

Ante todo, debo felicitarme a mi mismo. Este blog cumple 10 años. No voy a hacer el propósito de actualizarlo más a menudo (sobre todo porque no lo puedo mantener), pero seguirá existiendo por ahora.

¿Cómo ha ido cambiando el desarrollo web en estos años?

En 2005 teníamos la versión 5 de PHP recién salida del horno, la gente empezó a dejar de usar el "register_globals" (lo que costó...). No obstante, durante mucho tiempo se siguió utilizando PHP 4 en muchos sitios.

Por entonces se empezó a extender la idea en el mundillo PHP de que separar la lógica de la presentación era bueno y se empezó a extender el uso de motores de plantillas como Smarty. Parece que no, pero empezar a ver código PHP limpio de echo y sprintf fue un alivio.

Perl seguía fuerte en desarrollo web (Movable Type,...). Python no tenía mucha relevancia en el desarrollo web y Ruby era prácticamente un desconocido por estos lares.

Afortunadamente, ya empezaba a calar la idea entre los responsables IT de que quizás hacer las webs con tecnología J2EE no era lo adecuado en todos los casos. El tiempo nos ha dado la razón a los que pensábamos que era viable realizar proyectos de envergadura mantenibles con lenguajes de scripting.

Un punto de inflexión en el desarrollo web fue la aparición y popularización de varias soluciones que simplificaban mucho el trabajo: los frameworks. En el lado del servidor, herramientas como Ruby On Rails, Symfony, Django, y similares demostraron que era posible hacer aplicaciones web sin tener que estar tirando consultas SQL a pelo y manteniendo el código de forma organizada y previsible. En el lado cliente, las librerías de Javascript Prototype y jQuery (entre otras) nos ayudaron a abstraernos en cierta forma de las peculiaridades de cada navegador.

En 2008 ocurrieron dos cosas muy interesantes: llegaron los primeros iPhone a España y se lanzó el navegador Chrome. Nada ha vuelto a ser igual. Desde ese momento, Internet Explorer empezó a perder cuota de mercado inexorablemente.

2007

2015

Recuerdo alguna anécdota de entonces: le pregunté a un responsable editorial...
"Si la cuota de usuarios de alguna de las versiones de Internet Explorer baja del 5%, ¿nos autorizas a dejar de darle soporte?"

Je, je, je. A día de hoy, ya no tenemos que dar soporte a los Explorer más antiguos. Los diseñadores y maquetadores respiran aliviados.

Por otra parte, el incremento de uso de los teléfonos móviles con navegador nos obligó a todos a empezar a hacer webs diferenciadas para estos dispositivos.

De esta época también data la locura de las "apps". Todo el mundo quería tener una app, sin saber ni siquiera diferenciar una app nativa de un acceso directo en el "escritorio" del móvil con el iconito a la versión web. El tiempo parece que también ha colocado las cosas en su sitio. No era normal que unos dispositivos con un navegador tan completo (el Safari de los iPhone o el stock browser de Android, ambos basados en Webkit, también estaba el Opera Mini) necesitasen una aplicación nativa para mostrar lo que el navegador podía hacer perfectamente.

En 2010 se empezó a comercializar el iPad y poco después todas las tabletas de otros fabricantes. Otro cachivache más al que dar soporte. La maquetación y diseño se han complicado bastante, así que se ha terminado haciendo un diseño único que se adapte al dispositivo en el que se ve la página. No era viable tener tres versiones diferentes de una misma web, una para "desktop", otra para tablet y otra para móvil.

JavaScript ha evolucionado mucho y parece que prácticamente está estandarizado. Librerías como jQuery, Motools,.. y multitud de frameworks y librerías han surgido para facilitarnos el trabajo. Ya no vemos cosas como document.getElementById().

El lenguaje se ha rehabilitado a los ojos de los desarrolladores. JS ya no es el lenguaje que se usa para hacer monerías en una página web. Es un estándar, con muchas implementaciones y ya no está restringido a ejecutarse en el navegador. Node.js es la implementación más conocida de JS fuera del navegador, pudiendo correr en el "backend".

La sintaxis de objetos de JS (JSON) se ha convertido en muchos casos en el formato estándar "de facto" para intercambiar información estructurada, desplazando al voluminoso XML.

AJAX... Asynchronous Javascript And Xml... las siglas se han quedado, pero nadie utiliza ya XML para intercambiar datos, mejor JSON, que es más compacto y se parsea más rápido.

HTML5, casi más una buzzword que otra cosa. Pero está muy  bien tener un <video>, <audio> y <canvas> nativos y estructurar un poco mejor el HTML (<header>, <section>, <footer>,...), pero parece que no nos terminamos de quitar de encima al COBOL de la web: Flash.

Volviendo a JavaScript, en los últimos años ha habido una "explosión" de utilidades, implementaciones, frameworks y librerías. Los que nos hemos quedado un poco en la parte del desarrollo del backend estamos un poco desconcertados (yo al menos).

La última tecnología que se ha popularizado y ha pasado a ser "mainstream" en los últimos años son las bases de datos no relacionales (NoSQL). Otro campo en el que profundizar, sobre todo los que hemos seguido en el paradigma relacional.

Pese a todos estos cambios, hay una constante que permanece: hacer webs se lleva mucho tiempo. Tenemos mejores herramientas y entornos, pero los requisitos ahora son mucho más exigentes.

jueves, 29 de julio de 2010

Monitorizar un Apache que se cuelga

Hay veces que tenemos problemas en un servidor de producción y tenemos que mantenerlo en pie sea como sea hasta que encontramos una solución.

Se me ocurrió que, si miraba en el log de apache y buscaba la cadena típica que deja el PHP (o lo que esté fastidiando) cuando se "estropea", podría automatizar el reinicio del servidor hasta que diese con el problema. En mi caso, el mod_php5 hacía que el Apache se muriese con un "segmentation fault".

Éste es mi sencillo "script":


LINEAS=20
TOPE=18
CADENA="exit signal Segmentation fault"
REINICIAR="service httpd restart"
FICHREPORTE="/root/resultadosReinicios.log"
FICHLOG="/var/log/httpd/error_log"
NUMLINEASCHUNGAS=`tail --lines=$LINEAS $FICHLOG | grep "$CADENA" | wc -l`

if [ $NUMLINEASCHUNGAS -gt $TOPE ]; then
$REINICIAR
echo `date` ": se ha reiniciado el apache." >> $FICHREPORTE
cat From: `hostname`
To: mi@direccion.correo
Subject: Acabo de reiniciar el Apache

Hola, soy el script que monitoriza el Apache de `hostname` y lo acabo de reiniciar.
EOF

fi


La finalidad de este script es poderte ir a dormir y al menos estar tranquilo durante la noche sin que el teléfono suene ;-)
En distros de la "familia Debian" se reiniciaría el Apache con un /etc/init.d/apache2 restart

miércoles, 23 de septiembre de 2009

Algunos fallos tontos en el desarrollo web con PHP

¿A qué desarrollador web no le ha pasado alguna vez tener algo que no funciona, probar mil cosas y luego darse cuenta que era un error o fallo trivial? Para tirarse de los pelos, ¿verdad? Voy a relatar algunos.

  • ¿Por qué no entra por el if?
    Este es típico: un if que controla una sóla condición. Ejemplo en PHP, pero aplicable a cualquier lenguaje -excepto Python :-)
    loQueSea();
    if ($varControl)
    hazAlgo();
    otraCosa();

    Al cabo de un rato piensas que  si entra por el if, además debes cambiar otra variable y escribes:
    loQueSea();
    if ($varControl)
    hazAlgo();
    $otraVarControl = true;
    otraCosa();

    Y nunca consigues que otraVarControl se quede a true. ¿Qué pasa aquí? Fácil: no hemos puesto llaves al if.
    Conclusión: aunque el if sólo controle una sentencia, mejor con llaves siempre. Al final siempre va a haber más de una sentencia bajo ese if:
    loQueSea();
    if ($varControl) {
    hazAlgo();
    $otraVarControl = true;
    }
    otraCosa();


  • ¡No pilla los cambios!
    Es la típica llamada de un cliente (o un jefe): ¡me has dicho que cambiaste el XXX y no lo veo, sigue como antes!
    Nuestro XXX puede ser un fichero .js, un .css, una imagen o cualquier otro tipo de recurso que estamos seguros que hemos actualizado y que aún así, nos dicen que no lo ven.
    A los desarrolladores web no nos gustan mucho las cachés, ni proxies, etc, y además nos conocemos todos los típicos trucos para hacer un refresco completo de la página, pero nuestros jefes, clientes y usuarios sí que utilizan cachés (en el navegador, en su proxy). Además no se saben esos "mágicos" atajos de teclado que utilizamos sistemáticamente (Ctrl-Shift-R, Ctrl-F5 en IE) para ver cómo va nuestro trabajo en el navegador.
    Solución: forzar el refresco. Supongamos el siguiente HTML que incluye un .js sobre el cual hemos hecho cambios importantes:



    ...

    Subimos el fichero actualizado al hosting o servidor de producción, hacemos la llamada o enviamos el correo de rigor ("oye, ya está hecho") y al rato tenemos el típico "yo lo veo como antes".
    Nuestro fallo: presuponer que el entorno del usuario es el mismo que el nuestro. Puede que esté navegando a través de un proxy (suelen guardar en caché los elementos que le solicitan), su navegador puede estar configurado para que también "cacheé" algunos recursos, etc.
    La solución más fácil es añadir un "query string" a la llamada al recurso. Esto nos garantiza que será tratado como un fichero diferente y cargado de nuevo:



    ...

    Nos da igual cuál es esta "query string", simplemente lo que queremos es que todos los proxies, navegadores y demás clientes entiendan que es un recurso diferente. Este truco es válido para CSS, imágenes, swf. Por ejemplo, en la regla CSS:

    div.cabecera {background-image: http://mi.servidor.com/img/fondo.png?r=1}

    Si se tiene todo el trabajo integrado en un sistema de control de versiones, es muy útil configurar nuestro "deploy" para que este "parámetro" tome siempre el número de versión. Si estamos desarrollando la aplicación todavía, el truco infalible para que el navegador siempre lea los recursos como "nuevos" es hacer las llamadas así en nuestro fichero .php:



    <script src="fichero.js?version=" type="text/javascript">
    <link href="fichero.css?version="  rel="stylesheet" type="text/css" />

  • Página en blanco, no se ve nada. ¿Qué falla?
    Este típico error suele pasar cuando PHP está configurado para no mostrar ningún error (lo más recomendable en producción). Las soluciones son dos:

    • Editar el php.ini y cambiar el ajuste "display_errors" (nada recomendable).

    • Escribir la siguiente instrucción para saltarnos este ajuste para un "script" en concreto:
      <?php
      ini_set('display_errors', 1);
      // Sigue nuestro script

      La función ini_set() permite ajustar parámetros de configuración para un script determinado. Es muy útil cuando algo falla y no vemos dónde.



  • Los usuarios de mi aplicación no pueden hacer "login", o unos acceden al perfil del otro.
    Este es un error bastante insidioso y puede tener diferentes orígenes. Hay que conocer cómo maneja PHP las sesiones: PHP asigna al usuario una 'cookie' única con el identificador de sesión. En el servidor se guardan ficheros de sesiones en un directorio, un fichero para cada sesión 'asignada' a un usuario. Problemas potenciales:

    • El usuario no está aceptando cookies: en este caso es imposible que PHP asocie una sesión y sus datos con un usuario. Se puede configurar para que PHP mande el identificador de sesión en la URL, pero no es nada recomendable. Se puede comprobar si el usuario acepta cookies intentando enviarle una y leyéndola a continuación. Si no la tenemos, sacamos una advertencia al usuario.

    • El directorio del servidor donde se guardan las cookies no está accesible (problemas de permisos, falta de espacio, etc).

    • Si tenemos una configuración con balanceo de carga (varios servidores atendiendo a la misma URL) tenemos que asegurarnos que una vez que un usuario 'entra' por un servidor, sigue siempre en el mismo servidor. Otra solución es guardar las sesiones en una base de datos en vez de almacenarlas como ficheros.




Hay muchísimos más fallos tontos que nos podemos encontrar, pero éstas son algunas de las que más tiempo me han hecho perder ;-)

martes, 3 de marzo de 2009

Las elecciones desde el punto de vista informático

Pasada la resaca electoral, les voy a contar un poco por encima cómo trabajamos y lo que hacemos cuando hay elecciones.

Lo habitual es contactar unas semanas antes con el organismo responsable y solicitar una acreditación. En las elecciones que hemos cubierto hasta ahora (Generales 2009, Galicia y País Vasco 2009) el mecanismo ha sido similar: el organismo nos facilita una página web de acceso restringido desde la cual podemos descargar los ficheros con los datos de los recuentos.

Por lo general, antes del día "D" se ofrece una simulación con datos de prueba para que los medios podamos comprobar que nuestros desarrollos funcionan.

El formato de los datos no es estándar, cada organismo ofrece el que mejor le parece. En las pasadas elecciones generales se nos ofrecían un fichero de texto (comprimido) con los datos del recuento a nivel estatal, autonómico y provincial y otro conjunto de ficheros (también comprimidos) con el desglose del recuento por municipios.

Con antelación se nos facilitó la documentación sobre el formato de estos ficheros (por ejemplo: campo 1, tres posiciones, código del municipio; campo 2, dos posiciones, provincia; ....; campo n, código del partido, campo n+1, votos, ...)

Por fortuna, en las elecciones gallegas han utilizado un sistema informático similar, que emitía ficheros de datos muy parecidos, así que gran parte del trabajo ya lo teníamos hecho. Variaba la forma de desglosar: a nivel autonómico, provincial, comarcal y por municipios.

El Gobierno Vasco facilitaba los datos en un fichero XML único, en el cual también se desglosaban los datos a nivel autonómico, provincial y por municipios.

Una vez que hemos escrito el programa o "script" que analiza estos ficheros de datos, lo más conveniente es guardarlos en una base de datos relacional y escribir las consultas contra esta base de datos.

Como los ficheros de datos se van actualizando cada poco tiempo, lo más práctico es dejar que la computadora haga ella sóla el trabajo. En el caso de los datos del País Vasco, la dirección y nombre del fichero de datos ha sido toda la noche la misma, con lo que pudimos dejar un "script" corriendo cada minuto mientras pedíamos una pizza.

Los ficheros de datos del recuento en Galicia cambiaban de nombre cada vez que se actualizaba el recuento. Esto nos obligó a hacer un poco de trabajo manual, aunque lo teníamos también "semi-automatizado": llamábamos a un "script" pasándole el nombre de fichero de datos y se disparaba la actualización.

Por otra parte, en la página web se iba mostrando una especie de "marcador" con los datos parciales, el porcentaje escrutado, etc. Obviamente, estos datos provenían de nuestra base de datos, pero no podíamos arriesgarnos a que cada página vista disparase una consulta a la base de datos: saturaríamos los (ya bastante congestionados) servidores rápidamente.

La solución que adoptamos fue la siguiente: un "script" generaba un fragmento de HTML (haciendo las pertinentes consultas) cada 30 segundos, lo escribía en un fichero y lo que la página web mostraba era este HTML "precompilado". Bueno, bonito y barato ;-)Por otra parte, el lunes por la mañana, previendo que íbamos a tener muchas consultas para buscar municipios, resultados por comarcas, etc, en las páginas de resultados, decidimos "cachear" o guardar los resultados de las consultas, ya que estaba todo escrutado. De esta forma nos ahorramos muchas consultas a la base de datos, que suele ser el cuello de botella de las aplicaciones web.

Si usted busca los resultados electorales de su pueblo y la página tarda un poco en mostrarle los resultados, está de enhorabuena: es usted la primera persona que busca los resultados de este municipio, y, además, los siguientes usuarios que busquen los resultados de este mismo sitio tendrán una respuesta mucho más rápida.

Espero que les haya interesado esta entrada. Si quieren que les cuente algo más, dejen un comentario. Contestaré lo que mejor pueda.

viernes, 20 de febrero de 2009

El desarrollo de una página web

Me ha dado mucha envidia José Pujol con sus "posts" en los que explica el día a día de su trabajo, así que en esta entrada voy a hacer lo mismo.

En la web de Público tenemos dos partes muy diferenciadas: el gestor de contenidos y las páginas que genera (básicamente, la portada, las subportadas y las páginas con noticias) y el resto (blogs, video, sección de cine, archivos estáticos, etc).

Hoy voy a tratar de contar cómo hemos construido la página web del concurso Foto Libre.

Lo primero que hicimos fue reunirnos con la gente del periódico que organizaba el concurso (departamentos de fotografía, "marketing" y sistemas). En esta reunión se estableció la mecánica del concurso desde un punto de vista genérico, sin entrar en detalles técnicos.
Esta fase se suele denominar "toma de requisitos" y es fundamental para que un proyecto salga adelante. Tienen que quedar perfectamente especificadas todas las características deseables.

Con esta información, desde la parte de diseño y programación web (nosotros) se hicieron unos bocetos o esquemas de las páginas. Por ejemplo: "pantalla de inicio, desde ahí el usuario puede ir al formulario de registro o a la galería de fotos", o "pantalla de registro, el usuario introduce sus datos para participar y se le envía un correo de confirmación", etc.
Existe un término llamado "casos de uso" que sirve para documentar las posibles interacciones y flujo de trabajo de una aplicación.
En este punto, todavía no se ha escrito nada de código, pero son pasos necesarios para que todo salga bien. Si no está claro qué se quiere obtener, difícilmente el proyecto será del gusto del peticionario.

Cuando todos los implicados han dado el visto bueno a estos bocetos, empieza el trabajo de los diseñadores (Matteo y Daniel) y programadores (Rodrigo y el autor de estas líneas).

El separar funciones es bueno y productivo y permite avanzar en paralelo. Mientras los diseñadores van esbozando las distintas pantallas, los programadores vamos haciendo el trabajo "de trastienda": diseño de la base de datos (si es necesaria, claro), elección de la tecnología que se utilizará en el desarrollo (lenguajes de programación, "frameworks", etc), diseño funcional de la aplicación (separación de las distintas funcionalidades de la aplicación), etc.

En este punto, los diseñadores nos proveen con algunos archivos HTML y CSS estáticos. Los programadores los "desmenuzamos" y asignamos a cada parte de la aplicación una labor, algunas de estas unidades funcionales son las que se encargan de generar el HTML de forma dinámica (obteniendo los datos de las fotos de una base de datos, validando los datos que introducen los usuarios cuando se registran o suben fotos, etc).
Es la llamada "capa de presentación".

Hoy en día muchas webs se diseñan siguiendo un patrón o modelo muy conocido: MVC (Modelo, Vista, Controlador).
La capa M (modelo) abstrae, representa y ofrece mecanismos de acceso a los datos "crudos" de la aplicación, la capa C (controlador) se ocupa de gestionar las peticiones de las distintas páginas y solicitar los datos para generar estas páginas.
Por último, la capa V (vista o presentación) "pinta" o representa los datos en un formato determinado (en nuestra aplicación de Foto Libre, en HTML).

Para muchas páginas web sencillas o informales esta separación está casi más en la mente de las persona que escribe el código, pero en desarrollos de mayor entidad conviene separar físicamente estas funcionalidades.

Espero no haberles aburrido mucho. Es difícil condensar en unas pocas líneas tanta información. Otro día les contaremos más cosas sobre el trabajo que hacemos.