jueves, 21 de enero de 2016

Clasificación de lenguajes de programación en 2015

Infographic in DZone.com

Según Dzone.com:

  1. Javascript
  2. Java
  3. Python
  4. PHP
  5. C
  6. C++
  7. Ruby
  8. C#
  9. Objective-C
  10. Perl
  11. Css 3
  12. SQL
  13. Bash
  14. R
  15. Scala
  16. Matlab
  17. Visual Basic
  18. Haskell
  19. Go
  20. .Net
  21. Swift
  22. Clojure
  23. Groovy

domingo, 3 de enero de 2016

Menú de inicio desaparecido en Windows 10

Vamos con la primera entrada del año.

No acostumbro a usar sistemas Windows pero tengo un PC con Windows 10 para juegos1, para hacer pruebas y porque siempre conviene saber como va todo. Como decía, suelo usar ese PC para jugar por lo que es una máquina potente (Core i7, 16 GB de RAM, GTX 750 Ti, etc.), lo convierte en ideal para probar diferentes distribuciones de Linux en máquina virtual. Así que estaba yo el otro día tratando de instalar Xubuntu 15.10 en VirtualBox cuando sin saber bien como me cargué el menú de inicio, la barra de tareas y buena parte de la aplicaciones de Windows 10.

El escritorio funcionaba perfectamente, pero no podía acceder al menú de inicio, no aparecían los programas abiertos en la barra de tareas, el reloj y los iconos de la barra de estado habían desaparecido y los programas nuevos tampoco funcionaban (configuración del sistema, visor de fotos, etc.). En cambio podía ejecutar sin problema Firefox o Chrome e incluso el propio Virtual Box. También funcionaban los juegos (por ejemplo World of Warcraft). Reiniciar el sistema no sirvió para nada así que me puse a investigar.

Buscando buscando he encontrado que es un problema bastante común que lleva ocurriendo desde las primeras versiones preview de Windows 10. Hay varios artículos que tratan del tema como este, este, este, este o este, pero ninguna de las soluciones propuestas parecían funcionar.

Al final encontré el artículo Has your Windows 10 Start menu stopped working? Here are four ways to fix it que es una recopilación de todas las técnicas que puedes aplicar para solucionar el problema de menos agresiva a más agresiva. Al final lo que me funcionó a mi fue crear un nuevo usuario desde el Poweshell, reiniciar el PC y entrar con el nuevo usuario, pero ya llevaba probadas unas cuantas cosas por lo que bien pudo ser una combinación de factores.

Notas

[1] La principal función de ese PC es jugar y tiene Windows porque, reconozcámoslo, en Linux jugar es difícil. Steam es un gran avance pero configurar correctamente los drivers de la tarjeta gráfica es misión imposible. Ni los controladores libres ni los privativos funcionan como lo hacen en Windows. Y eso suponiendo que existan controladores para tu tarjeta gráfica.

viernes, 11 de diciembre de 2015

PHP 7.0.0 liberado

Acaba de hacerse oficial el lanzamiento de PHP 7.0.0. La nueva versión del lenguaje incluye numerosas mejoras y sobre todo un aumento de rendimiento considerable. Algunas de las nuevas características de PHP 7 son:

  • Tipo de retorno en las funciones: Por fin se podrá declarar que devuelve una función o método. Esta es una característica que siempre he echado en falta en PHP. Sobre todo cuando se diseñan interfaces o clases abstractas, poder indicar que debe devolver un método es algo muy útil. Ejemplos.
  • Declaración de tipos escalares: Se trata de poder definit el tipo de una variable para int, float, string y bool. Esto es útil por ejemplo para definir los parámetros de una función o método. También se definen dos niveles de exigencia: normal y estricto. El segundo se controla mediante la directiva declare(strict_types=1); (en la primera línea del script) e implica un control estricto de los tipos escalares provocando errores de tipo E_RECOVERABLE_ERROR en caso de incumplimiento. Ejemplos.
  • Nuevo operador ?? (coalesce): El operador de doble interrogación ?? permite devolver un valor específico si una variable no está definida. Por ejemplo $username = $_GET('username') ?? null; sería equivalente a $username = isset($_GET('username')) ? $_GET('username') : null;. Ejemplos.
  • Nuevo operador de comparación <=> (spaceship): La operación $a <=> $b devuelve 0 si $a y $b son iguales; devuelve -1 si $a es menor que $b; y devuelve 1 si $a es mayor que $b. Es decir lo mismo que strcmp() pero no limitado a strings. Funciona con variables de tipo int, float, string, array e incluso object. Ejemplos.
  • Sintaxis uniforme de variables: Se ha añadido soporte completo a construcciones de variables complejas, pero con consistencia. Por ejemplo [$obj1, $obj2][0]->prop, $foo->bar()(), (function() { ... })(), "string"->toLower(), etc. Ejemplos.
  • Solución de errores históricos.

Enlaces

miércoles, 2 de diciembre de 2015

Ya está aquí Symfony 3

SensioLabs ha anunciado esta semana la liberación de dos nuevas versiones del popular framework Symfony: La 2.8, que es la última versión de Symfony 2 y cuenta con soporte extendido; y la esperada versión 3.0 que inaugura la tercera iteración del framework PHP.

La versión 2.8 cuenta con retrocompatibilidad con las anteriores versiones de Symfon 2, mientras que la versión 3.0 elimina todas las funciones obsoletas (deprecated) que se han ido sustituyendo en las sucesivas versiones de Symfony 2. Es decir en esencia las versiones 2.8 y 3.0 de Symfony son idénticas excepto que la versión 2.8 mantiene la retrocompatibilidad con las versiones anteriores mientras que la 3.0 no lo hace.

La liberación de las nuevas versión hace que actualmente haya cinco versiones de Symfony con soporte:

Versión LTS Liberación Soporte bugs Soporte seguridad
2.3 x MAY-2013 MAY-2016 MAY-2017
2.6 NOV-2014 JUL-2015 ENE-2016
2.7 x MAY-2015 MAY-2018 MAY-2019
2.8 x NOV-2015 NOV-2018 NOV-2019
3.0 NOV-2015 JUL-2016 ENE-2017

La siguiente versión LTS (Long Time Suport) de Symfony está previsto que sea la 3.3 y la fecha prevista para su liberación es Mayo de 2017. Por ello si hay que empezar un proyecto nuevo con Symfony lo recomendable por ahora es usar la versión 2.8 que tiene 5 años de soporte, teniendo cuidado de no usar funciones obsoletas de Symfony 2 de forma que en el futuro sea factible realizar la migración a Symfony 3.

Enlaces

jueves, 19 de noviembre de 2015

¿Como evitar bloqueos de sesión en PHP?

PHP

Por defecto PHP escribe los datos de la sesión en un fichero en disco. La función session_start() bloquea el fichero de la sesión de forma que nadie más puede leerlo. Ese bloqueo durará hasta que se acaba la ejecución del script o hasta que se libere manualmente usando alguna de las siguientes funciones: session_abort(), session_commit(), session_destroy() o session_write_close().

El problema

La mayoría de los programadores inician la sesión al principio del script, pero la dejan abierta hasta el final. Eso en entornos con múltiples peticiones sobre la misma sesión (por ejemplo con mucho AJAX) es posible que acabe causando un cuello de botella en momentos putuales. En el momento que una petición tarde demasiado en responder (debido por ejemplo a una query complicada) las demás peticiones no podrán acceder al fichero de sesión que estará bloqueado con el resultado de un tiempo de respuesta significativamente elevado. Pero sólo en momentos puntuales.

La solución

Lo más fácil es liberar el fichero de sesión justo después del session_start(). Los datos de sesión seguirán disponibles para lectura a través de la variable superglobal $_SESSION, pero no se podrá encribir nada en la sesión.

<?php
// Start the session
session_start();

// Session is open to read/write ops
$_SESSION['latestRequestTime'] = time();

// Close the session
session_write_close();

// Now session is read-only
$user = $_SESSION['userNAme'];

Alternativas

Si no es posible cerrar la sesión justo después de abrirla (por ejemplo porque haya que escribir datos después de obtenerlos y/o procesarlos) hay algunas alternativas que pueden utilizarse: Guardar la sesión en una base de datos MySQL, ya que el motor de base de datos no bloquea la sesión, o bien guardar la sesión en algún sistema de caché como Redis, Memcache, etc.

Enlaces

jueves, 22 de octubre de 2015

Evitando el consumo excesivo de memoria con Doctrine y Symfony2

Doctrine es el ORM que utiliza el framework Symfony2. Es un producto muy completo, con muchas opciones, pero tiene un pequeño problema cuando se manejan grandes cantidades de información.


El problema

He tenido un problema con un script que mantiene sincronizadas dos bases de datos (una MySQL y otra PostgreSQL, en servidores remotos, aunque no venga al caso). Se trata de un comando de consola de Symfony2 que se ejecuta periódicamente a través de un cron. Llevaba meses funcionando bien hasta que de repente:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1454 bytes).

Vi el problema enseguida: La cantidad de datos a sincronizar ha crecido últimamente; Así que rediseñé el algoritmo para que funcionase con bloques de 500 registros en lugar de tratar de golpe todos los registros.

Pero eso no solucionó el problema.


La solución

Podría haber puesto el sufrido ini_set("memory_limit", -1) pero eso sólo haría que el proceso gastase más y más memoria del sistema. El recolector de basura de PHP no libera los objetos mientras haya referencias apuntando a los mismos y Doctrine internamente mantiene esas referencias a no ser que se liberen manualmente.

Para ello el EntityManager de Doctrine en Symfony2 cuenta con un par de funciones: detach y clear. Veamos un ejemplo:

$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('...')->findBy(array('...'));
foreach ($entities as $entity) {
    $entity->doSomething();
    // (....)
    $em->detach($entity);
    unset($entity);
}
$em->clear();

La instrucción detach desvincula una entidad del EntityManager; es decir elimina cualquier referencia a la entidad. Los cambios realizados en la entidad, incluyendo su borrado, no se sincronizarán con la base de datos posteriormente a la desvinculación. Por su parte clear desvincula de golpe todas las entidades cargadas en el EntityManager.


Referencias

miércoles, 8 de abril de 2015

¿Como poner en producción un proyecto Symfony 2?

Symfony 2 es uno de los frameworks MVC basados en lenguaje PHP que más de moda están en los últimos tiempos. La documentación oficial de Symfony 2 es muy extensa, pero se hecha en falta una sección dedicada sobre como poner en producción un proyecto ya terminado (o una beta) en un servidor real. Lo que llamamos desplegar el proyecto (del inglés deploy).

Los requisitos de Symfony 2 no son demasiado elevados: Basta un servidor web como Apache o Nginx y PHP 5.3.3 o superior (aunque se recomienda PHP superior a 5.3.16). Siempre es recomendable aunque no obligatorio que sea un servidor dedicado sobre el que tengamos acceso root. Es perfectamente posible desplegar un proyecto Symfony 2 en un servidor compartido aunque eso sí: es necesario tener acceso al shell del servidor (vía SSH típicamente). Symfony 2 no puede desplegarse simplemente subiendo los archivos por FTP.


Conceptos previos

Cualquier proyecto Symfony 2 está compuesto por una carpeta de código fuente del proyecto (src), una carpeta de librerías externas entre las que se incluye el propio framework (vendors), una carpeta de configuración y recursos globales (app) y una carpeta frontal (web). Todas ellas son necesarias, pero no todas tienen la misma importancia.

Carpetas de un proyecto Symfony

  • app: Esta carpeta contiene la configuración del proyecto (subcarpeta app/config), pero también los recursos comunes (subcarpeta app/Resources), los logs (subcarpeta app/logs) y también la cache (subcarpeta app/cache), que es donde se crean una serie de clases autogeneradas que aceleran la ejecución del proyecto (es algo similar a tener código compilado sólo que sigue siendo PHP). En la carpeta app también está la consola que es un componente necesario para instalar el proyecto.
  • src: Esta carpeta contiene el código fuente del proyecto. Internamente el código se divide en bundles y cada bundle puede tener controladores, entidades, vistas, recursos, etc.
  • vendor: Esta carpeta contiene el código fuente de las librerías externas y bundles que usa el proyecto. Se trata de código es open-source que sus creadores ponen a disposición de los programadores para desarrollar sus propios proyectos.
  • web: Esta carpeta contiene el controlador frontal de Symfony 2 (programa app.php). Un proyecto Symfony 2 puede tener más de un controlador frontal, según los distintos entornos de ejecución que se definan: app_dev.php, app_test.php, etc. A la hora de ponerlo en explotación bastaría con el controlador frontal del entorno de producción producción. En la carpeta web también se copian automáticamente los assets del proyecto (imágenes, CSS, JS, etc.)

Entornos de un proyecto Symfony

Dentro de un único proyecto Symfony 2 se pueden definir diversos entornos; típicamente son tres, aunque pueden ser más: desarrollo (dev), pruebas (test) y producción (prod). El primero se usa para desarrollar en proyecto, el segundo es para pasar los test unitarios y funcionales y el tercero es para probar el proyecto tal y como debe funcionar en explotación.

Ojo: Nunca han que confundir los entornos de Symfony (dev, test, prod) con los entornos de una organización. Son cosas distintos. A la hora de poner en producción un proyecto Symfony 2 en un servidor real sólo tendremos en cuenta el entorno de producción. Los demás deben descartarse.

Cada entorno Symfony 2 tiene archivos de configuración diferentes en la carpeta app/config:

  • config.yml: Archivo de configuración común para todos los entornos.
  • config_dev.yml: Archivo de configuración del entorno de desarrollo de Symfony 2. Modifica la configuración de config.yml para el entorno dev. Permite por ejemplo evitar que se envíen mails al ejecutar los test.
  • config_test.yml: Archivo de configuración del entorno Symfony 2 de pruebas unitarias.
  • config_prod.yml: Archivo de configuración específico del entorno de producción.

Además del archivo de configuración puede haber otros archivos con configuración adicional:

  • security.yml: Configuración de la seguridad del proyecto Symfony 2.
  • routing.yml: Configuración de las rutas del proyecto Symfony 2.
  • routing_dev.yml, routing_test.yml, … rutas adicionales por entornos.

Por último existen dos archivos de configuración adicionales:

  • parameters.yml: Este archivo contiene la configuración dependiente de la instalación y es el único archivo que debería variar de un servidor a otro. Sirve por ejemplo para indicar la base de datos a usar, el servidor del API, el servidor de correo, etc. NUNCA debería distribuirse este archivo en una puesta en explotación.
  • parameters.yml.dist: Indica los valores por defecto del archivo “parameters.yml” y es usado por “composer.phar” para crear este último.

Por cada entorno Symfony 2 también habrá un controlador frontal en la carpeta web. Es decir que además del controlador app.php podremos tener app_dev.php y app_test.php. Si por ejemplo creamos un archivo config_beta.yml automáticamente se creará un controlador app_beta.php.

Herramientas

  • composer.phar: Herramienta para resolver dependencias en un proyecto PHP. Usado por Symfony 2 para instalar los vendor y para preparar los entornos.
  • app/console.php: Herramienta interna de Symfony 2 que permite limpiar la cache, instalar los assets y muchas más cosas.

Punto de partida

Para poner en producción un proyecto Symfony 2 hay dos puntos de partida:

  1. Partir de un repositorio (GIT, SVN, etc.)
  2. Partir de código fuente con los vendor.

Permisos

Debido a que es necesario que las carpetas app/cache y app/logs tengan permiso de escritura se recomienda que el usuario Linux que realice la instalación sea el mismo del servidor web (apache, nginx, etc). Si esto no fuera posible debería modificarse el propietario de todos los archivos de esas carpetas como paso final de la instalación o bien dar permisos de escritura sobre esas carpetas. Si esto no se hace no funcionará el proyecto.


Partiendo de un repositorio (GIT, SVN, etc.)

Pasos a seguir

  1. Copiar el proyecto desde el repositorio.
  2. Instalar los vendor.
    php composer.phar install
  3. Borrar controladores frontales y archivos de configuración sobrantes.
    rm -f app/config/*_dev.yml
    rm -f app/config/*_test.yml
    rm -f web/app_dev.yml
    rm -f web/app_test.yml
    (...)
  4. Copiar el archivo app/config/parameters.yml específico de esta instalación.
  5. Limpiar e inicializar la cache de Symfony 2.
    php app/console -e=prod cache:clear
  6. Instalar los assets del entorno de producción.
    php app/console assets:install web --symlink
    php app/console -e=prod assetic:dump
  7. Opcionalmente cambiar el propietario de las carpetas cache y logs.
    chown -R nginx:nginx app/cache
    chown -R nginx:nginx app/logs
  8. Opcionalmente dar permisos de escritura a las carpetas cache y logs.
    chmod -R a+w app/cache
    chmod -R a+w app/logs

Partiendo del código fuente completo (incluido vendor).

Lo normal es que un proyecto Symfony 2 se despliegue desde un repositorio de fuentes (GIT, SVN, etc), pero en ocasiones esto no es posible. En ese caso habrá que subir manualmente el código fuente al servidor, incluyendo la carpeta vendor.

Pasos a seguir

  1. Copiar todo el proyecto Symfony 2 a la carpeta de destino.
  2. Borrar las carpetas de “cache” y “logs”.
    rm -rf app/cache/*
    rm -rf app/logs/*
  3. Borrar controladores frontales y archivos de configuración sobrantes.
    rm -f app/config/*_dev.yml
    rm -f app/config/*_test.yml
    rm -f web/app_dev.yml
    rm -f web/app_test.yml
    (...)
  4. Copiar el archivo app/config/parameters.yml específico de esta instalación.
  5. Limpiar e inicializar la cache de Symfony 2.
    php app/console -e=prod cache:clear
  6. Instalar los assets del entorno de producción.
    php app/console assets:install web --symlink
    php app/console -e=prod assetic:dump
  7. Opcionalmente cambiar el propietario de las carpetas cache y logs.
    chown -R nginx:nginx app/cache
    chown -R nginx:nginx app/logs
  8. Opcionalmente dar permisos de escritura a las carpetas cache y logs.
    chmod -R a+w app/cache
    chmod -R a+w app/logs