<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TecnoRetales</title>
	<atom:link href="http://www.tecnoretales.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.tecnoretales.com</link>
	<description>La experiencia no se olvida</description>
	<lastBuildDate>Sat, 05 Dec 2009 14:31:42 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Symfony i18n con gettext</title>
		<link>http://www.tecnoretales.com/programacion/symfony-i18n-con-gettext/</link>
		<comments>http://www.tecnoretales.com/programacion/symfony-i18n-con-gettext/#comments</comments>
		<pubDate>Sat, 05 Dec 2009 14:26:01 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=716</guid>
		<description><![CDATA[Symfony permite varios métodos para internazionalizar nuestra aplicación. Por defecto, utilizan el formato XLIFF sin embargo, personalmente me gusta más gettext.
¿Cómo configurar symfony para usar gettext?
Para configurar symfony para que utilice gettext seguiremos los siguientes pasos:
1) Activamos el módulo I18N modificando el archivo settings.yml:
#apps/&#60;appName&#62;/config/settings.yml
all:
  .settings:
    charset:      [...]]]></description>
			<content:encoded><![CDATA[<p>Symfony permite varios métodos para <strong>internazionalizar</strong> nuestra aplicación. Por defecto, utilizan el <a title="Formato XLIFF" href="http://es.wikipedia.org/wiki/XLIFF" target="_blank">formato XLIFF</a> sin embargo, personalmente me gusta más <a title="Gettext" href="http://es.wikipedia.org/wiki/Gettext" target="_blank">gettext</a>.</p>
<p><strong>¿Cómo configurar symfony para usar gettext?</strong></p>
<p>Para configurar symfony para que utilice <strong>gettext</strong> seguiremos los siguientes pasos:</p>
<p>1) Activamos el módulo I18N modificando el archivo <strong>settings.yml</strong>:</p>
<pre class="brush: php;">#apps/&lt;appName&gt;/config/settings.yml
all:
  .settings:
    charset:                utf-8
    i18n:                   on
    standard_helpers:       [ [TUS_HELPERS_ACTIVADOS]..., I18N]</pre>
<p>2) Abrimos el archivo <strong>factories.yml</strong> y añadimos la entrada i18n:</p>
<pre class="brush: php;">#apps/&lt;appName&gt;/config/factories.yml
all:
  i18n:
    class: sfI18N
    param:
      default_culture:  en_US
      source:           gettext&lt;/pre&gt;
</pre>
<p>3) Crearemos una carpeta i18n dentro de <em>apps/<appName>/</em>:</p>
<pre class="brush: php;">apps/&lt;appName&gt;/i18n/&lt;lang&gt;</pre>
<p>Donde &lt;lang&gt; será el idioma en dos letras (en, es, fr&#8230;) y dentro tendremos los ficheros messages.po y messages.mo.</p>
<p>Ahora podemos utilizar la función __( &#8216;texto_a_traducir&#8217; ) con doble <em>underscore</em> [ _ ] en lugar del simple utilizado normalmente.</p>
<p><strong>¿Cómo generar automáticamente nuestros ficheros po y mo?</strong></p>
<p>Symfony trae una serie de herramientas que nos permiten generar los archivos po y mo de manera automática. Invocando el comando:</p>
<p><code>symfony i18n:extract frontend en --auto-save</code></p>
<p>Se recorrerá todos los archivos php de nuestra aplicación (código y templates) y sacará los textos que encuentre en las funciones __().</p>
<p>También se puede utilizar el mismo comando de la siguiente manera:</p>
<p><code>symfony i18n:extract frontend en --auto-delete</code></p>
<p>para eliminar las cadenas de texto que ya no existen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/symfony-i18n-con-gettext/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pasar segundos a horas:minutos:segundos</title>
		<link>http://www.tecnoretales.com/programacion/pasar-segundos-a-horas-minutos-segundos/</link>
		<comments>http://www.tecnoretales.com/programacion/pasar-segundos-a-horas-minutos-segundos/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 21:34:31 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Script]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=711</guid>
		<description><![CDATA[Una sencilla función que dado un número de segundos, nos devuelve el tiempo en formato hh:mm:ss


protected function makeTimeFromSeconds( $total_seconds )
{
    $horas              = floor ( $total_seconds / 3600 );
    $minutes            = ( ( $total_seconds / 60 ) % 60 );
    $seconds        [...]]]></description>
			<content:encoded><![CDATA[<p>Una sencilla función que dado un número de segundos, nos devuelve el tiempo en formato hh:mm:ss</p>
<pre class="brush: php;">

protected function makeTimeFromSeconds( $total_seconds )
{
    $horas              = floor ( $total_seconds / 3600 );
    $minutes            = ( ( $total_seconds / 60 ) % 60 );
    $seconds            = ( $total_seconds % 60 );

    $time['horas']      = str_pad( $horas, 2, &quot;0&quot;, STR_PAD_LEFT );
    $time['minutes']    = str_pad( $minutes, 2, &quot;0&quot;, STR_PAD_LEFT );
    $time['seconds']    = str_pad( $seconds, 2, &quot;0&quot;, STR_PAD_LEFT );

    $time               = implode( ':', $time );

    return $time;
}
</pre>
<p>Espero os sea de utilidad.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/pasar-segundos-a-horas-minutos-segundos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>La clase sfConfig de Symfony</title>
		<link>http://www.tecnoretales.com/programacion/la-clase-sfconfig-de-symfony/</link>
		<comments>http://www.tecnoretales.com/programacion/la-clase-sfconfig-de-symfony/#comments</comments>
		<pubDate>Sat, 10 Oct 2009 21:05:27 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Frameworks]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Symfony]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=701</guid>
		<description><![CDATA[Aquí os dejo algo de información sobre como solicitar variables de configuración en symfony además de un listado muy útil con todas las variables que Symfony trae predefinidas.
Cómo pedir variables definidas
Se puede llamar a la función estática get del objeto sfConfig para solicitar cualquier variable definida pasándo dos valores. El primero indica el nombre de [...]]]></description>
			<content:encoded><![CDATA[<p>Aquí os dejo algo de información sobre como solicitar variables de configuración en symfony además de un listado muy útil con todas las variables que Symfony trae predefinidas.</p>
<h3>Cómo pedir variables definidas</h3>
<p>Se puede llamar a la función estática get del objeto sfConfig para solicitar cualquier variable definida pasándo dos valores. El primero indica el nombre de la variable solicitada y el segundo, el valor que retornará en caso de no existir dicha variable.</p>
<pre><strong>sfConfig::get('sf_config_variable', 'The default value'); </strong>// The default is optional</pre>
<p><span id="more-701"></span>Además de las variables que symfony trea configuradas por defecto, podemos añadir nuestras propias variables. Esto se hace en los archivos app.yml. Tenemos un app.yml global para todas las aplicaciones y módulos de nuestro proyecto localizado en:</p>
<pre>/path/to/project/[PROJECT_NAME]/config/app.yml</pre>
<p>y otro para cada una de las aplicaciones:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/config/app.yml</pre>
<p>NOTA! Si existen dos variables con el mismo nombre en el app.yml global y en el de aplicación, este último valor sobreescribirá el valor global.</p>
<p>Para solicitar una variable definida en uno de estos archivos app.yml devemos añadir app_ al nombre de la variable como se muestra en el siguiente ejemplo:</p>
<pre>sfConfig::get('<strong>app_</strong>sf_config_variable');</pre>
<p>Si en el archivo app.yml definimos la variable en cascada, como por ejemplo:</p>
<pre>all:
  admin:
    email: admin@mail.bla
</pre>
<p>Deberemos acceder a ella añadiendo los diferentes niveles en la llamada:</p>
<pre>sfConfig::get('<strong>app_</strong>admin_email');
También podemos acceder a los valores configurados en settings.yml añadiendo el prefijo “sf_” al valor que queremos recuperar.
</pre>
<h3>Variables definidas por Symfony Framework</h3>
<pre><strong>sf_symfony_lib_dir</strong></pre>
<p>Path real a la carpeta lib del framework:</p>
<pre>/usr/share/php/symfony/symfony12/lib</pre>
<h3>Project Structure and Layout</h3>
<pre><strong>sf_root_dir</strong></pre>
<p>Path a la raiz del projecto:</p>
<pre>/path/to/project/[PROJECT_NAME]</pre>
<pre><strong>sf_apps_dir</strong></pre>
<p>Path a la carpeta &#8220;apps&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps</pre>
<pre><strong>sf_lib_dir</strong></pre>
<p>Path a la carpeta &#8220;lib&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/lib</pre>
<pre><strong>sf_log_dir</strong></pre>
<p>Path a la carpeta &#8220;log&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/log</pre>
<pre><strong>sf_data_dir</strong></pre>
<p>Path a la carpeta &#8220;data&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/data</pre>
<pre><strong>sf_config_dir</strong></pre>
<p>Path a la carpeta &#8220;config&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/config</pre>
<pre><strong>sf_test_dir</strong></pre>
<p>Path a la carpeta &#8220;test&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/test/</pre>
<pre><strong>sf_doc_dir</strong></pre>
<p>Path a la carpeta &#8220;doc&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/doc</pre>
<pre><strong>sf_plugins_dir</strong></pre>
<p>Path a la carpeta de &#8220;plugins&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/plugins</pre>
<pre><strong>sf_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;cache&#8221; del proyecto:</p>
<pre>/path/to/project/[PROJECT_NAME]/cache</pre>
<pre><strong>sf_web_dir</strong></pre>
<p>Path a la carpeta pública &#8220;web&#8221;:</p>
<pre>/path/to/project/[PROJECT_NAME]/web</pre>
<pre><strong>sf_upload_dir</strong></pre>
<p>Path a la carpeta pública de &#8220;uploads&#8221;:</p>
<pre>/path/to/project/[PROJECT_NAME]/web/uploads</pre>
<h3>Application Information</h3>
<pre><strong>sf_app</strong></pre>
<p>El nombre de la aplicación en la que está el archivo, como por ejemplo &#8220;frontend&#8221; o &#8220;backend&#8221;.</p>
<pre><strong>sf_environment</strong></pre>
<p>Entorno de desarrollo actual como por ejemplo &#8220;dev&#8221;.</p>
<pre><strong>sf_debug</strong></pre>
<p>Devuelve el estado actual del modo debug. Puede estar activado &#8220;1&#8243; o desactivado &#8220;0&#8243;.</p>
<h3>Application Structure and Layout</h3>
<pre><strong>sf_app_dir</strong></pre>
<p>Path a la carpeta de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]</pre>
<pre><strong>sf_app_config_dir</strong></pre>
<p>Path a la carpeta &#8220;config&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/config</pre>
<pre><strong>sf_app_lib_dir</strong></pre>
<p>Path a la carpeta &#8220;lib&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/lib</pre>
<pre><strong>sf_app_module_dir</strong></pre>
<p>Path a la carpeta &#8220;modules&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/modules</pre>
<pre><strong>sf_app_template_dir</strong></pre>
<p>Path a la carpeta &#8220;templates&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/templates</pre>
<pre><strong>sf_app_i18n_dir</strong></pre>
<p>Path a la carpeta &#8220;i18n&#8221; de la aplicación actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/i18n</pre>
<h3>Cache Structure and Layout</h3>
<pre><strong>sf_app_base_cache_dir</strong></pre>
<p>Path a la carpeta de la aplicación actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]</pre>
<pre><strong>sf_app_cache_dir</strong></pre>
<p>Path a la carpeta de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev</pre>
<pre><strong>sf_template_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;template&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/template</pre>
<pre><strong>sf_i18n_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;i18n&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/i18n</pre>
<pre><strong>sf_config_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;config&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/config</pre>
<pre><strong>sf_test_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;test&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/test</pre>
<pre><strong>sf_module_cache_dir</strong></pre>
<p>Path a la carpeta &#8220;modules&#8221; de la aplicación actual en el entorno de desarrollo actual dentro de la caché.</p>
<pre>/path/to/project/[PROJECT_NAME]/cache/[APP_NAME]/dev/modules</pre>
<h3>Application Settings</h3>
<pre><strong>sf_error_404_module</strong></pre>
<p style="padding-left: 30px;">Módulo que ha hecho saltar el error 404.</p>
<pre><strong>sf_error_404_action</strong></pre>
<p style="padding-left: 30px;">Acción que ha hecho saltar el error 404.</p>
<pre><strong>sf_logging_enabled</strong></pre>
<p style="padding-left: 30px;">Valor boleano que nos indica si el loggin de la web está activo &#8220;1&#8243; o no &#8220;0&#8243;.</p>
<pre><strong>sf_escaping_strategy</strong></pre>
<p style="padding-left: 30px;">Valor boleano que indica si la clase sfView está usando Escaping Strategy &#8220;1&#8243; o no &#8220;0&#8243;.</p>
<pre><strong>sf_no_script_name</strong></pre>
<p style="padding-left: 30px;">Valor boleano que indica si la aplicación requiere nombre de script.</p>
<pre><strong>sf_csrf_secret</strong></pre>
<p style="padding-left: 30px;">La clave CSRF secreta configurada en la aplicación.</p>
<h3>También:</h3>
<p>Se puede acceder a la información del actual contexto con las siguientes funciones:</p>
<pre><strong>sfContext::getInstance()-&gt;getActionName();</strong></pre>
<p>Devuelve el nombre de la acción actual. También puede llamarse desde los templates con  $this-&gt;getActionName().</p>
<pre><strong>sfContext::getInstance()-&gt;getModuleName();</strong></pre>
<p>Nombre del módulo actual. También puede llamarse desde los templates con $this-&gt;getModuleName().</p>
<pre><strong>sfContext::getInstance()-&gt;getModuleDirectory();</strong></pre>
<p>Path al directorio del módulo actual:</p>
<pre>/path/to/project/[PROJECT_NAME]/apps/[APP_NAME]/modules/[MODULE_NAME]</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/la-clase-sfconfig-de-symfony/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Si las webs fueran personas&#8230;</title>
		<link>http://www.tecnoretales.com/internet/si-las-webs-fueran-personas/</link>
		<comments>http://www.tecnoretales.com/internet/si-las-webs-fueran-personas/#comments</comments>
		<pubDate>Mon, 05 Oct 2009 17:40:14 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Humor]]></category>
		<category><![CDATA[YouTube]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=697</guid>
		<description><![CDATA[Veo en el blog de 20 minutos la siguiente viñeta que identifica las webs más populares del momento con personas.
]]></description>
			<content:encoded><![CDATA[<p>Veo en el <a title="Blog 20 Minutos" href="http://blogs.20minutos.es/becario/post/2009/09/20/si-webs-fueran-personas-" target="_blank">blog de 20 minutos</a> la siguiente viñeta que identifica las webs más populares del momento con personas.<a href="http://www.tecnoretales.com/wp-content/uploads/2009/10/blog-silaswebsfuerangente-d.jpg"><img class="aligncenter size-full wp-image-698" title="blog-silaswebsfuerangente-d" src="http://www.tecnoretales.com/wp-content/uploads/2009/10/blog-silaswebsfuerangente-d.jpg" alt="blog-silaswebsfuerangente-d" width="544" height="151" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/internet/si-las-webs-fueran-personas/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Cómo optimizar tus aplicaciones Web</title>
		<link>http://www.tecnoretales.com/programacion/como-optimizar-tus-aplicaciones-php/</link>
		<comments>http://www.tecnoretales.com/programacion/como-optimizar-tus-aplicaciones-php/#comments</comments>
		<pubDate>Fri, 02 Oct 2009 16:57:21 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Navegadores]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Optimización]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHPBarcelona]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=685</guid>
		<description><![CDATA[Manuel Aguilar publicó una magnífica presentación sobre cómo optimizar aplicaciones Web dada en la PHP Barcelona Conference 2008 y he considerado interesante recopilar a modo de resumen las ideas más importantes de ese artículo, en cualquier caso, recomiendo la lectura del mismo para recoger toda su esencia y ampliar información.
Partiendo de un estudio de Yahoo! [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tecnoretales.com/wp-content/uploads/2009/10/internet-speed.jpg"><img class="alignleft size-full wp-image-693" title="Optimizar aplicaciones PHP" src="http://www.tecnoretales.com/wp-content/uploads/2009/10/internet-speed.jpg" alt="Optimizar aplicaciones PHP" width="200" height="200" /></a>Manuel Aguilar publicó una magnífica presentación sobre cómo <strong>optimizar aplicaciones Web</strong> dada en la PHP Barcelona Conference 2008 y he considerado interesante recopilar a modo de resumen las ideas más importantes de ese artículo, en cualquier caso, recomiendo la lectura del mismo para recoger toda su esencia y ampliar información.</p>
<p>Partiendo de un estudio de Yahoo! que dice que el 80% del tiempo de carga de una web corresponde al lado del cliente, podemos seguir una serie de reglas que aumentarán significativamente la percepción de velocidad del usuario.<span id="more-685"></span></p>
<p><strong>1. Aumentar el tiempo de expiración</strong> de los elementos cacheados que no varían como CSS o JavaScript: Para forzar la carga de los mismos cuando haya cambios, podemos añadir el md5 del contenido del fichero como parámetro, así el navegador lo recargará cuando cambie el hash. Ej: style.css?hash=f9d35dcf65d8f67e288ae2f12fc069f7</p>
<p><strong>2. No colocar código JavaScript o estilos inline</strong>: es mejor colocarlos como ficheros externos fácilmente cacheables, de este modo evitaremos descargar todo el html por un cambio de estilo.</p>
<p><strong>3. Reducir el número de ficheros externos</strong>: Los navegadores sólo pueden aceptar dos descargas simultaneas de un mismo dominio, si unimos nuestras librerías JavaScript y nuestros CSS en un único archivo evitaremos dilatar innecesariamente el tiempo de descarga.</p>
<p><a href="http://www.tecnoretales.com/wp-content/uploads/2009/10/firebug.jpg"><img class="aligncenter size-full wp-image-686" title="Firebug Net" src="http://www.tecnoretales.com/wp-content/uploads/2009/10/firebug.jpg" alt="Firebug Net" width="582" height="149" /></a></p>
<p><strong>4. Usar subdominios</strong> diferentes para las imágenes y para los elementos estáticos: Conseguiremos así descargar 8 elementos de manera simultánea y reducir la carga de la web. Si además podemos optimizar un apache aparte para servir las imágenes, conseguiremos un mejor rendimiento al servirlas.</p>
<p><strong>5. Compactar los ficheros JavaScript</strong>: Existen programas gratuitos como <a title="Yui Compressor" href="http://yuilibrary.com/downloads/#yuicompressor" target="_blank">YUI Compressor</a> que comprimen los archivos JavaScript consiguiendo resultados de hasta el 50%.</p>
<p><strong>6. Utilizar compresión en el servidor</strong>: Los servidores modernos como Apache son capaces de comprimir la información antes de servirla, posteriormente los navegadores actuales como Explorer o Firefox la descomprimen de manera transparente al usuario.</p>
<p><strong>7. Fomentar el uso de imágenes con muchos sprites</strong>: Estas son imágenes grandes que contienen muchas imágenes pequeñas. Según lo comentado en el punto 3 tardaremos mucho menos en descargar una imágen con 50 sprites que 50 sprites de manera individual. Posteriormente utilizaremos CSS para definir la sección de imágen que se mostrará.</p>
<p><a href="http://www.tecnoretales.com/wp-content/uploads/2009/10/sprites.jpg"><img class="aligncenter size-full wp-image-687" title="Sprites" src="http://www.tecnoretales.com/wp-content/uploads/2009/10/sprites.jpg" alt="Sprites" width="336" height="153" /></a></p>
<p><strong>8. Mover los CSS al &lt;head&gt;</strong>: Navegadores como Explorer no renderizan la web hasta que no tienen todos los CSS, si los colocas en la cabecera podrá empezar antes a mostrar la web.</p>
<p><strong>9. Mover los JavaScript al final de la página</strong>: Hasta que un fichero JavaScript no se ha leido completamente el navegador no continua con la carga. Si los movemos al final de la página este se estará cargando cuando el usuario ya está navegando por la web.</p>
<p><strong>10. Evitar llamadas duplicadas a JavaScript y CSS</strong>: Si el navegador encuentra un fichero JavaScript para la carga hasta que este se ha leido completamente, si posteriormente vuelve a encontrar una llamada al mismo JS, volverá a parar la carga hasta que se haya leido.</p>
<p style="text-align: right;">Vía | <a title="Optimización aplicaciones PHP" href="http://www.slideshare.net/maguilar/phpbarcelona-conference-optimizacin-aplicaciones-php-client-side" target="_blank">Optimización aplicaciones PHP</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/como-optimizar-tus-aplicaciones-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implementando un sistema de caché en PHP</title>
		<link>http://www.tecnoretales.com/programacion/implementando-un-sistema-de-cache-en-php/</link>
		<comments>http://www.tecnoretales.com/programacion/implementando-un-sistema-de-cache-en-php/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 09:40:24 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Caché]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=658</guid>
		<description><![CDATA[Hace unos días, os comentaba que es una caché y como entenderla en el marco de la programación web. Para seguir con el aprendizaje de este sistema, he desarrollado una pequeña clase que permite cachear información (strings, arrays, resultados de base de datos, objetos&#8230;) en nuestra máquina y descongestionar así el motor de base de [...]]]></description>
			<content:encoded><![CDATA[<p>Hace unos días, os comentaba <a title="Qué es una caché?" href="http://www.tecnoretales.com/programacion/que-es-una-cache-y-como-aplicarla-a-la-programacion-web/" target="_blank">que es una caché</a> y como entenderla en el marco de la programación web. Para seguir con el aprendizaje de este sistema, he desarrollado una pequeña <strong>clase que permite cachear información</strong> (strings, arrays, resultados de base de datos, objetos&#8230;) en nuestra máquina y descongestionar así el motor de base de datos, por poner un ejemplo.</p>
<p>Lo primero que debemos hacer es <strong>pensar en que necesitamos</strong> para su correcto funcionamiento, así que, manos a la obra.</p>
<p>Como sabemos, una caché es un sistema al que le pasamos un objeto X y él lo almacenará en su sistema de una manera determinada, por lo tanto, necesitaremos una función que dado un identificador único y unos datos, guardará la información. Además de esto, necesitamos indicarle un <strong>tiempo de vida</strong> (ttl) a esa información cacheada, sino estaremos devolviendo eternamente el valor almacenado.<span id="more-658"></span></p>
<p>Un concepto que nos puede resultar interesante es el de <strong>caché de grupo</strong>. Imaginemos que tenemos un sistema que va cacheando información de nuestra base de datos; tenemos una tabla user y una tabla user_profile y cacheamos los resultados de ambas tablas por separado. Imaginemos también que por temas de LOPD el usuario solicita que eliminemos todos sus datos de nuestras máquinas, así que eliminaremos el registro de la tabla user y user_profile y procederemos a eliminar el cacheo de los datos de cada tabla por separado. Si tuviesemos agrupada la información de usuario, con una única llamada a la función remove y pasándole el identificador de grupo, eliminará la caché de ambas tablas.</p>
<p>A medida que vaya explicando cada función, os pondré el resultado final para que os hagais una idea de como va quedando el código:</p>
<pre class="brush: php;">
    public function save ( $id, $group_id = 'default', $data, $ttl = self::CACHE_TTL )
    {
        if ( $this-&gt;caching )
        {
            $this-&gt;set_file_routes( $id, $group_id );

            // If the directory don't exists, I create.
            if ( !is_dir ( $this-&gt;file_path ) )
            {
                if ( !mkdir ( $this-&gt;file_path, 0777, true ) )
                {
                    return false;
                }
            }

            if ( !is_array ( $data ) &amp;amp;&amp;amp; !is_object( $data ) )
            {
                $data = array ( $data );
            }

            // Serialize data for caching.
            $data = serialize ( $data );

            // I get a hash to check integrity in the future.
            $hash = md5 ( $data );

            $meta['expiration_time']    = time () + $ttl;
            $meta['integrity']          = $hash;
            $meta['data']               = $data;

            // Serialize meta info to put in a file.
            $data    = serialize ( $meta );

            return file_put_contents ( $this-&gt;file, $data, LOCK_EX );
        }

        return false;
    }</pre>
<p>A su vez, debemos poder recuperar los objetos almacenados en un futuro, así que también programaremos una función que dado un identificador y un identificador de grupo, devolverá unos datos <strong>get($id, $group_id)</strong>. El tener que pasar el identificador de grupo en esta función es debido a que las rutas de almacenamiento se generan a partir de ambos identificadores.</p>
<pre class="brush: php;">
    public function get ( $id, $group_id = 'default' )
    {
        if ( $this-&gt;caching )
        {
            $this-&gt;set_file_routes ( $id, $group_id );

            if ( !file_exists ( $this-&gt;file ) )
            {
                return false;
            }

            $meta    = file_get_contents ( $this-&gt;file_path . $this-&gt;file_name );
            $meta    = unserialize ( $meta );

            $check_expiration   = $this-&gt;check_expiration ( $meta['expiration_time'] );
            $check_integrity    = $this-&gt;check_integrity ( $meta['integrity'], $meta['data'] );

            // Expiration and integrity control.
            if ( $check_expiration &amp;amp;&amp;amp; $check_integrity )
            {
                $data = unserialize ( $meta['data'] );

                return $data;
            }
            else
            // Clean the expired or not correct caché.
            {
                $this-&gt;remove ( $id, $group_id );

                return false;
            }
        }

        return false;
    }
</pre>
<p>Como último elemento fundamental, necesitaremos poder borrar unos datos de la caché en caso de que ya no sean válidos porque se han modificado o borrado, así que crearemos una función que dado un identificador y un identificador de grupo, elimine el objeto cacheado. A esta función la llamaremos <strong>remove($id, $group_id)</strong>.</p>
<pre class="brush: php;">
    public function remove( $id, $group_id = 'default', $group_level = false )
    {
        $this-&gt;set_file_routes( $id, $group_id );

        // Don't remove the 'default' group
        if ( $group_level &amp;amp;&amp;amp; $group_id != 'default' )
        {
            if ( !$this-&gt;group_path || empty ( $this-&gt;group_path ) )
            {
                return false;
            }

            return $this-&gt;del_tree ( $this-&gt;group_path );
        }
        // Check that the file exists and delete the file cached folder
        elseif ( $this-&gt;file_path &amp;amp;&amp;amp; !empty ( $this-&gt;file_path ) )
        {
            return $this-&gt;del_tree ( $this-&gt;file_path );
        }
        else
        {
            return false;
        }
    }
</pre>
<p>Como sabemos, la caché guarda los objetos durante un tiempo determinado y una vez ha pasado ese tiempo, el objeto se considera inservible, por lo tanto añadiremos una función <strong>check_expiration()</strong> que nos dirá si el objeto está caducado.</p>
<pre class="brush: php;">
private function check_expiration ( $expiration_time )
{
return ( time() &lt; $expiration_time );
}
</pre>
<p>¿Qué pasa si cuando estoy almacenando los datos hay un problema de escritura y los datos se almacenan mal? Podría suceder que los <strong>datos almacenados esten corruptos</strong>, y todas las devoluciones de dicho objeto fueran defectuosas. Para comprobar que los datos guardados no están corruptos, crearemos una función <strong>check_integrity()</strong>.</p>
<pre class="brush: php;">
    private function check_integrity ( $read_hash, $serialized_data )
    {
        $hash = md5 ( $serialized_data );

        return ( $read_hash == $hash );
    }
</pre>
<p>Además de estas funciones, crearemos varias constantes que definirán los valores de configuración del sistema como pueden ser el tiempo de vida (ttl) de un objeto cacheado por defecto o el directorio en el que se guardará la caché.</p>
<pre class="brush: php;">
    // Path to cache dir.
    const CACHE_DIR = 'cache/';

    // Max. time to life of this cache.
    const CACHE_TTL = '3600';

    // Extension to use in cache files.
    const CACHE_EXT = '.cache';
</pre>
<p>En el código se llama a las funciones <strong>get_status()</strong> y <strong>set_status()</strong> que sirven comprobar si está activo el sistema de cacheo y habilitar/deshabilitar respectivamente. <strong>set_file_routes()</strong> crea las rutas en las que se almacenará los datos cacheados y <strong>get_key()</strong> crea hashes a partir de un identificador. Por último, <strong>del_tree()</strong> nos ayudará a eliminar un directorio de manera recursiva.</p>
<pre class="brush: php;">
    public function get_status ()
    {
        return $this-&gt;caching;
    }

    public function set_status ( $status )
    {
        $this-&gt;caching = $status;
    }

    private function set_file_routes ( $id, $group_id )
    {
        $key_name    = $this-&gt;get_key ( $id );
        $key_group   = $this-&gt;get_key ( $group_id );

        $level_one = $key_group;
        $level_two = substr ( $key_name, 0, 4 );

        $this-&gt;group_path   = self::CACHE_DIR . $level_one . '/';
        $this-&gt;file_path    = self::CACHE_DIR . $level_one . '/' . $level_two . '/';
        $this-&gt;file_name    = $key_name . self::CACHE_EXT;
        $this-&gt;file         = $this-&gt;file_path . $this-&gt;file_name;
    }

    private function get_key ( $id )
    {
        return md5 ( $id );
    }

    private function del_tree ($dir)
    {
        if ( empty ( $dir ) )
        {
            return false;
        }

        if ( !file_exists ( $dir ) )
        {
            return true;
        }

        if ( !is_dir ( $dir ) || is_link ( $dir ) )
        {
            return unlink ( $dir );
        }

        foreach ( scandir ( $dir ) as $item )
        {
            if ( $item == '.' || $item == '..' )
            {
                continue;
            }

            if( is_dir ( $dir . $item ) )
            {
                $this-&gt;del_tree ( $dir . $item . '/' );
            }
            else
            {
                unlink ( $dir . $item );
            }
        }

        return rmdir ( $dir );
    }
</pre>
<p>Puedes descargarte el archivo final desde aquí <a href="http://www.tecnoretales.com/wp-content/uploads/2009/09/cache.class.php.txt" target="_blank">cache.class.php</a>.</p>
<p>Aunque esta caché es perfectamente funcional, este ejercicio nos sirve para <strong>entender un poco más el funcionamiento de un sistema de caché</strong>. Si queremos implementar uno en nuestra aplicación, os recomiendo mirar <a title="CacheLite" href="http://pear.php.net/package/Cache_Lite" target="_blank">CacheLite</a> (si nuestra aplicación es pequeña), <a title="APC" href="http://es2.php.net/apc" target="_blank">APC</a> o <a title="Memcached" href="http://www.danga.com/memcached/" target="_blank">Memcached</a> (si nuestra aplicación es grande y/o con servidores balanceados).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/implementando-un-sistema-de-cache-en-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google compra ReCaptcha para impulsar Google Books</title>
		<link>http://www.tecnoretales.com/internet/google-compra-recaptcha-para-impulsar-google-books/</link>
		<comments>http://www.tecnoretales.com/internet/google-compra-recaptcha-para-impulsar-google-books/#comments</comments>
		<pubDate>Fri, 18 Sep 2009 23:57:10 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Google]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=675</guid>
		<description><![CDATA[Google vuelve a ser noticia, esta vez por la compra de la empresa ReCaptcha encargada de facilitar un sistema rápido y eficaz de captcha a webmasters para utilizar en sus proyectos web. Con esta adquisición, Google pretende acelerar el proceso de digitalización de libros para Google Books, proyecto en el que lleva trabajando varios años.
¿Qué [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tecnoretales.com/wp-content/uploads/2009/09/recaptcha-example.gif"><img class="alignleft size-full wp-image-676" title="recaptcha-example" src="http://www.tecnoretales.com/wp-content/uploads/2009/09/recaptcha-example.gif" alt="recaptcha-example" width="314" height="125" /></a>Google vuelve a ser noticia, esta vez por la <strong>compra de la empresa ReCaptcha</strong> encargada de facilitar un sistema rápido y eficaz de captcha a webmasters para utilizar en sus proyectos web. Con esta adquisición, Google pretende acelerar el proceso de digitalización de libros para <a title="Google Books" href="http://books.google.com/" target="_blank">Google Books</a>, proyecto en el que lleva trabajando varios años.<span id="more-675"></span></p>
<h3>¿Qué es un captcha?</h3>
<p>Los captcha son esas &#8220;molestas&#8221; cajas con textos a menudo casi ilegibles que nos encontramos a la hora de registrarnos en una web, insertar un comentario blog&#8230;</p>
<p>La función de un captcha es la de asegurarnos que quien está realizando una acción, como las mencionadas anteriormente, sea una persona y no un programa (comunmente llamados bots). Para una máquina, el reconocimiento de textos distorsionados dentro de imágenes es un proceso bastante complejo (aunque no imposible), por lo tanto al colocar este tipo de sistemas en el registro de hotmail, por poner un ejemplo, estaremos eliminando el 99,9% de los registros automáticos por programas que después utilizan la cuenta para enviar spam.</p>
<h3>¿Por qué ha comprado Google la empresa ReCaptcha?</h3>
<p>Los emprendedores que iniciaron ReCaptcha pensaron que este sistema, además de ser muy útil para webmasters, podría ser también muy útil para que los usuarios del sistema fueran digitalizando poco a poco libros previamente escaneados y pasados por un OCR (software de reconocimiento óptico de caracteres).</p>
<p>Los OCR tienen muy buenos resultados en libros actuales con los caracteres bien definidos, pero en el caso de libros antiguos o en mal estado puede cometer un porcentaje muy elevado de errores:</p>
<p><a href="http://www.tecnoretales.com/wp-content/uploads/2009/09/sample-ocr.gif"><img class="aligncenter size-full wp-image-677" title="sample-ocr" src="http://www.tecnoretales.com/wp-content/uploads/2009/09/sample-ocr.gif" alt="sample-ocr" width="544" height="108" /></a></p>
<p>La idea es mostrar en los sistemas de captcha dos palabras, una conocida que será la encargada de validar correctamente el texto introducido por el usuario, y otra desconocida que <strong>el usuario se encargará de traducir</strong>.</p>
<p>Google ha visto en este sistema un filón para dar impulso a su macro proyecto Google Books,<a title="Google Books" href="http://books.google.com/" target="_blank"></a> proyecto que pretende <strong>digitalizar</strong> y poner a disposición de todos los internautas <strong>miles de libros</strong> para que puedan ser descargados de manera gratuita.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/internet/google-compra-recaptcha-para-impulsar-google-books/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Test-Driven Development</title>
		<link>http://www.tecnoretales.com/programacion/test-driven-development/</link>
		<comments>http://www.tecnoretales.com/programacion/test-driven-development/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 08:50:56 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[PHPUnit]]></category>
		<category><![CDATA[Unit Test]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=649</guid>
		<description><![CDATA[
Hace algún tiempo, os hablaba de la importancia de usar Unit Testing en nuestros desarrollos para tender localizados los posibles errores en cada una de nuestras funciones y, de ese modo, hacer un cambio en cualquier función no nos será crítico, ya que el test nos informará si la función está devolviendo los resultados esperados [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-650" title="test-driven_development" src="http://www.tecnoretales.com/wp-content/uploads/2009/09/test-driven_development.jpg" alt="test-driven_development" width="240" height="214" /></p>
<p>Hace algún tiempo, os hablaba de <a title="La importancia de usar Unit Testing" href="http://www.tecnoretales.com/programacion/unit-test-la-importancia-de-usar-tests-unitarios/" target="_blank">la importancia de usar Unit Testing</a> en nuestros desarrollos para tender localizados los posibles errores en cada una de nuestras funciones y, de ese modo, hacer un cambio en cualquier función no nos será crítico, ya que <strong>el test nos informará</strong> si la función está devolviendo los resultados esperados para cada cualquier.</p>
<p>Pero ¿y si al desarrollar el test me he dejado algún punto por comprobar? A menudo, tener una covertura del 100% resulta complicado debido al error humano, pero una vez detectado un error, debemos solventarlo y modificar el test para que no vuelva a darse ese error, y yendo un poco más allá, ¿por qué no <strong>pensar en los posibles errores</strong> que puede tener la función que desarrollemos antes de programarla? y ya que los hemos pensado, ¿por qué no realizar el test aunque todavía no hayamos desarrollado la función en questión? Pues precisamente, esa es la idea del Test-Driven Development (TDD a partir de ahora).</p>
<p>En resumen, podemos decir que el TDD es una práctica a la hora de programar que implica el desarrollo del <strong>test unitario</strong> antes de haber picado una sola línea del código de la función a testear&#8230; Pero, ¿qué ventajas tiene? ¿cuál es el workflow de esta práctica?<span id="more-649"></span></p>
<h3><span style="text-decoration: underline;">Ventajas de usar TDD</span></h3>
<p>Generalmente, somos <strong>escépticos a la hora de adoptar una nueva práctica</strong> como el Unit Testing o más aún, algo que parece tan ilógico como TDD, pues es costoso en tiempo para el programador el desarrollo del test (cuando lo que nos gusta es desarrollar cosas útiles y no aparentemente inútiles como una prueba) e implica tener que pensar un rato antes de desarrollar. Sin embargo, seguir esta forma de programación tiene una serie de ventajas que hacen decantar la balanza a su favor:</p>
<ol>
<li><strong><span style="text-decoration: underline;">Código de mayor calidad</span>:</strong> El hecho de desarrollar el test antes que la función a ser testeada, nos obliga a pensar en como será la función, ordenarla y ver que errores podrá haber. Esto hará que en el momento de empezar a picar la función, tengamos muy claro que es lo que queremos hacer y como, por tanto, el código será más limpio y concreto.</li>
<li><strong><span style="text-decoration: underline;">Desacoplo del código</span>:</strong> Cuando piensas en como será la función de manera que pueda ser testeada, te ves obligado a separar el bloque central en bloques más pequeños (que también serán testeados). De este modo, una función que podría ser muy compleja, acaba dividida en tres más pequeñas y fáciles de testear.</li>
<li><strong><span style="text-decoration: underline;">Disminución del tiempo de desarrollo</span>:</strong> Independientemente del coste en tiempo de desarrollar el test (pues doy por hecho de que estás convencido de su utilidad y lo desarrollarás igualmente), el desarollo de la función es más rápida porque ya hemos pensado que y como lo vamos a hacer, simplemente hay que picarlo.</li>
<li><strong><span style="text-decoration: underline;">Disminución del número de líneas</span>:</strong> TDD lleva implicita un proceso de refactorizando constante hasta que la función está acabada, gracias a eso, es fácil darnos cuenta que hemos complicado un proceso y lo podemos optimizar.</li>
</ol>
<h3><span style="text-decoration: underline;">Workflow</span></h3>
<p>Antes de comenzar el ciclo de trabajo se debe definir una lista de requerimientos. Luego se comienza el siguiente ciclo:</p>
<ol>
<li><strong>Elegir un requerimiento:</strong> Se elige de una lista el requrimiento que se cree que nos dará mayor conocimiento del problema y que a la vez sea fácilmente implementable.</li>
<li><strong>Escribir una prueba:</strong> Se comienza escribiendo una prueba para el requerimiento. Para ello el programador debe entender claramente las especificaciones y los requisitos de la funcionalidad que está por implementar. Este paso fuerza al programador a tomar la perspectiva de un cliente considerando el código a través de sus interfaces.</li>
<li><strong>Verificar que la prueba falla:</strong> Si la prueba no falla es porque el requerimiento ya estaba implementado o porque la prueba es errónea.</li>
<li><strong>Escribir la implementación:</strong> Escribir el código más sencillo que haga que la prueba funcione. Se usa la metáfora &#8220;Déjelo simple&#8221; (&#8221;Keep It Simple, Stupid&#8221; (KISS)).</li>
<li><strong>Ejecutar las pruebas automatizadas:</strong> Verificar si todo el conjunto de pruebas funciona correctamente.</li>
<li><strong>Eliminación de duplicación:</strong> El paso final es la refactorización, que se utilizará principalemente para eliminar código duplicado. Se hacen de a una vez un pequeño cambio y luego se corren las pruebas hasta que funcionen.</li>
<li><strong>Actualización de la lista de requerimientos:</strong> Se actualiza la lista de requerimientos tachando el requerimiento implementado. Asimismo se agregan requerimientos que se hayan visto como necesarios durante este ciclo y se agregan requerimientos de diseño (P. ej que una funcionalidad esté desacoplada de otra).</li>
</ol>
<p>Resumiendo en una imágen:</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-653" title="20090712160619!Test-driven_development" src="http://www.tecnoretales.com/wp-content/uploads/2009/09/20090712160619Test-driven_development.PNG" alt="20090712160619!Test-driven_development" width="615" height="441" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/test-driven-development/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Qué es una Caché y como aplicarla a la programación Web</title>
		<link>http://www.tecnoretales.com/programacion/que-es-una-cache-y-como-aplicarla-a-la-programacion-web/</link>
		<comments>http://www.tecnoretales.com/programacion/que-es-una-cache-y-como-aplicarla-a-la-programacion-web/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 08:15:27 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Caché]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Optimización]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=642</guid>
		<description><![CDATA[Vamos a ver que es una caché con un ejemplo muy ilustrativo que leí hace algún tiempo. Supongamos que estamos trabajando en una centralita que facilita números de teléfono de un pueblo relativamente pequeño; para ello, tenemos un listín telefónico común con todos los teléfonos del pais.
Cada vez que recibimos una llamada, cogemos el listín, [...]]]></description>
			<content:encoded><![CDATA[<p>Vamos a ver <strong>que es una caché</strong> con un ejemplo muy ilustrativo que leí hace algún tiempo. Supongamos que estamos trabajando en una centralita que facilita números de teléfono de un pueblo relativamente pequeño; para ello, tenemos un listín telefónico común con todos los teléfonos del pais.</p>
<p>Cada vez que recibimos una llamada, cogemos el listín, realizamos la búsqueda y facilitamos el número encontrado al usuario. Al poco tiempo, nos damos cuenta que la gente suele pedir los teléfonos de los mismos restaurantes y comercios una y otra vez, así que cogemos una libreta pequeña y vamos anotando los números de teléfono que nos solicitan ordenados alfabéticamente para poder <strong>acceder a ellos de manera más rápida</strong> la próxima vez&#8230; felicidades, acabas de crear una caché!<span id="more-642"></span></p>
<p>Sin embargo, el uso de una <strong>caché tiene un pequeño handicap</strong>; imaginemos que nos llama un usuario y nos solicita el teléfono de un comercio. Cogeremos nuestra libreta, lo buscaremos y si no lo encontramos recurriremos al listín, realizaremos la búsqueda en él y facilitaremos el número al usuario. En este momento estamos aumentando ligeramente el tiempo de búsqueda de un número, por ese motivo, la información debe almacenarse en la caché de manera eficiente, y a partir de aquí hay mil teorías sobre como y cuando almacenar la información en una caché.</p>
<p>En resumen y dicho de una manera más técnica un sistema de caché es una zona de memoria en la que se almacenan copias de un objeto original pero al que es mucho más rápido acceder.</p>
<h3><span style="text-decoration: underline;">La Caché en la programación</span>:</h3>
<p>A la hora de construir una aplicación medianamente grande, se hace imprescindible el cachear cierta información para conseguir un rendimiento óptimo. Un sistema de caché correctamente implementado puede <strong>reducir el número de servidores y evitar la sobrecarga</strong> de las máquinas.</p>
<p>Se pueden utilizar diferentes tipos de caché en función del tipo de datos que queramos guardar. Centrándome en la programación web, podemos encontrar:</p>
<ul>
<li><span style="text-decoration: underline;">Caché SQL</span>: Para almacenar en memoria el resultado de ciertas consultas recurrentes y poder así descargar la base de datos. MySQL 5.0 Server tiene soporte nativo para este tipo de caché pero se debe activar expresamente.</li>
<li><span style="text-decoration: underline;">Cachéo de Objetos</span>: En este tipo de caché podemos almacenar objetos, arrays, textos, resultados de funciones, resultados de base de datos&#8230; Podremos almacenar cualquier tipo de información soportada por el sistema de cacheo e indicarle el tiempo de expiración. Ejemplos de este sistema de caché para PHP son APC (Alternative PHP Cache) o Memcached.</li>
<li><span style="text-decoration: underline;">Cacheo de templates</span>: Puede ser de gran utilidad el cachear los resultados HTML al invocar diferentes URL, por ejemplo, el sistema de templates Smarty integra un sistema de caché que permite devolver el HTML de manera eficiente.</li>
</ul>
<h3><span style="text-decoration: underline;">Por qué no debo usar SQLCaché y APC o Memcached?</span></h3>
<p>La caché implementada por MySQL tiene una política en la gestión de su caché muy estricta. Cada vez que hay una escritura en una tabla, elimina toda la caché asociada a dicha tabla y a partir de ese momento, se debe volver a regenerar, por tanto, la entrada de un registro en la tabla implica insertar el registro, regenerar los indices, cachear los datos y por último devolverlos (aumentamos el tiempo de la consulta). Dada esta premisa, podemos extraer la conclusión de que es interesante <strong>activar SQLCaché en una base de datos con muchas lecturas y pocas escrituras</strong>.</p>
<p>A su vez, implementando un sistema de cacheo como APC o Memcached para almacenar la información devuelta por la base de datos dada una consulta, reduce considerablemente el número de lecturas a base de datos.</p>
<p>Por ese motivo, el tener activados estos dos tipos de caché simultaneamente, no solo no mejora el rendimiento de nuestra aplicación sino que lo empeora.</p>
<h3><span style="text-decoration: underline;">Es contraproducente usar APC y Memcached de manera simultanea?</span></h3>
<p>APC proporciona dos tipos de cacheo. Por un lado, evita el continuo compilado de un script PHP, pues a pesar de ser un lenguaje interpretado, PHP pasa todo script a un lenguaje entendible por la máquina antes de ejecutarlo ¿por qué recompilar cada vez el script si no ha cambiado desde la última ejecución? A partir de la versión 6 de PHP parece ser que APC estará activado de forma nativa. Por otra parte, podemos almacenar objetos con el uso de las funciones <a title="APC_add" href="http://es.php.net/manual/en/function.apc-add.php" target="_blank">apc_add</a> y <a title="APC_store" href="http://es.php.net/manual/en/function.apc-store.php" target="_blank">apc_store</a>.</p>
<p>Memcached proporciona un servicio web desacoplado y altamente escalable. <strong>El 95% del top ten y el 80% del top 50 de Alexa utiliza Memcached</strong> precisamente por la facilidad de implementación y de añadir nuevas máquinas para cachear información. APC tiene un rendimiento ligeramente superior, pero si tenemos un sistema con servidores balanceados no podemos compartir la caché entre todas las máquinas porque está vinculada al host, por ese motivo la balanza se ha ido decantando hacia el uso de Memcached.</p>
<p>Si bien, puede ser interesante <strong>utilizar una combinación de ambas</strong>, APC para el <strong>precompilado</strong> de nuestro código y <strong>Memcached para almacenar</strong> la información de base de datos y descargar así nuestro motor de bd.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/que-es-una-cache-y-como-aplicarla-a-la-programacion-web/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP Barcelona Conference 2009</title>
		<link>http://www.tecnoretales.com/programacion/php-barcelona-conference-2009/</link>
		<comments>http://www.tecnoretales.com/programacion/php-barcelona-conference-2009/#comments</comments>
		<pubDate>Fri, 11 Sep 2009 22:03:44 +0000</pubDate>
		<dc:creator>Manel Pérez Mata</dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PHPBarcelona]]></category>
		<category><![CDATA[PHPUnit]]></category>

		<guid isPermaLink="false">http://www.tecnoretales.com/?p=635</guid>
		<description><![CDATA[Después del éxito obtenido la pasada edición, el grupo PHPBarcelona ha vuelto a organizar una conferencia para este año. El lugar de encuentro será el CitiLab de Cornellà los días 30 y 31 de Octubre.
Ya se ha abierto la venta anticipada de entradas a un precio increiblemente bajo: 25€ un día y 40€ los dos. [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-636" title="phpbarcelonaconference2009" src="http://www.tecnoretales.com/wp-content/uploads/2009/09/phpbarcelonaconference2009.png" alt="phpbarcelonaconference2009" width="342" height="272" />Después del éxito obtenido la pasada edición, el grupo <a title="PHPBarcelona" href="http://phpbarcelona.org/" target="_blank">PHPBarcelona</a> ha vuelto a organizar una conferencia para este año. El lugar de encuentro será el <a title="CitiLab de Cornellà" href="http://citilab.eu/inici" target="_blank">CitiLab</a> de Cornellà los días 30 y 31 de Octubre.</p>
<p>Ya se ha abierto la venta anticipada de entradas a un precio increiblemente bajo: 25€ un día y 40€ los dos. Puedes adquirir las entradas desde la <a title="PHPBarcelona" href="http://phpbarcelona.org/venta-anticipada-de-entradas-para-la-conference-del-2009" target="_blank">web oficial</a>.</p>
<p>Según anuncian: &#8220;Este año el evento viene cargado de muchas e interesantes novedades: dos días de duración (Viernes y Sábado), <strong>distintas actividades</strong> entremezcladas (ponencias teóricas, talleres prácticos, concursos de programación, etc.), dos líneas de idioma (español e inglés), nuevos y potentes patrocinadores, más <strong>celebridades invitadas</strong>, divertidos regalos y mucho más!&#8221;</p>
<p>Realmente este año los chicos de PHPBarcelona se han puesto las pilas, pues en el cartel de charlas aparecen nombres tan importantes como <strong>Rasmus Lerdorf</strong> (Uno de los creadores de PHP), <strong>Fabien Potencier</strong> (Lead Developer de Symfony), <strong>Derick Rethans</strong> (XDebug) y <strong>Sebastian Bergmann</strong> (Creador de PHPUnit).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tecnoretales.com/programacion/php-barcelona-conference-2009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
