Monthly Archive for Agosto, 2009

Objetos maestros en PHP

Ya comenté el tema de usar clases “principales” para un proyecto… y ahora vuelvo con el mismo tema. Muy creativo, sí…

La idea es la de tener un objeto principal (maestro) con un constructor que crea dentro del propio objeto tantos objetos “internos” como hagan falta, pasándole por referencia su propio objeto al constuctor de los “objetos internos”.

Los “objetos internos” extienden a una plantilla de objeto, y esa plantilla contiene un constructor que a su vez “guarda” como referencia el parámetro pasado por el objeto principal.

Sí, es un lío, así que mejor verlo en código:

class AppObjectSkel {
  function __construct(&$parent) {
    $this->_parent = $parent;
    if(is_callable(array($this, 'init'))) $this->init();
  }
}

class AppDatabase extends AppObjectSkel {
  function init() {
    /* Aquí se inicializa la DB */
  }
}

class AppCache extends AppObjectSkel {
  /* Elemento de cache, no lo inicializamos en este ejemplo */
}

class Application {
  function __construct() {
    $this->database = new AppDatabase($this);
    $this->cache = new AppCache($this);
  }
}

De esta manera se puede acceder de un elemento a otro. Por ejemplo, desde AppCache se puede acceder a AppDatabase pasando por Application, simplemente usando $this->_parent->database. Al tratarse de un valor pasado por referencia, se puede acceder desde AppDatabase a AppCache y reflejar cambios en tiempo real.

Pero hay que tener en cuenta un pequeño detalle: los constructores. Debido a que se hereda de una clase maestra (AppObjectSkel), no se puede poner constructor de ningún tipo (ya sea __constructor o una función con el nombre de la clase), ya que PHP ejecutará únicamente el del objeto creado (AppCache, por ejemplo) y no el de AppObjectSkel (y mucho menos va a ejecutar dos constructores). Se puede evitar esto de varias formas: evitando AppObjectSkel en todos los casos y copiando el construct a cada vez, copiando el construct sólo cuando lo necesitamos (por que pisamos el construct de AppObjectSkel) o simplemente usar una función opcional (llamada init), como pongo en el ejemplo, que sólo se ejecuta si existe y se llama desde AppObjectSkel, a modo de constructor (un constructor invoca a otro).

Desde la propia aplicación simplemente hay que crear una nueva instancia del objeto Application ($app = new Application) y acceder a los diferentes objetos a partir del maestro ($app->db, $app->cache).

Esto llega a ser muy útil cuando la aplicación entera está divida en objetos (AppUsers, AppForums, AppProfiles...) y es necesario hacer transacciones entre los objetos. En lugar de crear una instancia para cada objeto cada vez que se necesitan (por ejemplo, instanciar AppCache desde AppUsers cuando hace falta usar memcache), se pueden instanciar una sola vez y acceder en un entorno protegido (Application, que vendría a ser un “contenedor” relativamente protegido de variables pisadas y globales erradas), a todos los objetos o variables que haga falta.

Con esto después se pueden hacer montones de cambios (instanciar una clase poco usada sólo cuando se necesita, hacer una especie de namespace para tener un cache durante la ejecución del programa…). Y es que ahí, la imaginación es el límite.

Sistemas de recomendaciones

Hace ya algún tiempo (casi 2 meses!) saqué showRSS junto con algunos amigos. Se trata de un servicio web que permite generar un feed completamente personalizable que contiene los torrents de las series seleccionadas por los usuarios, extrayendo los torrents (y por lo tanto, series cubiertas) de EZTV, con el objetivo de sustituir al difunto FeedMyTorrents. El servicio tuvo bastante éxito (portada en Digg, aparición en TorrentFreak, Lifehacker, AppleSfera, y de ahí bastantes más blogs de tamaño medio).

Pese a mis temores, aguantó demasiado bien el tirón, y lo mejor de todo, sin posteriores sorpresas (lecturas aleatorias que fallan, índices que revientan y demás marrones aleatorios que suelen surgir). De ahí (y después del «hype») me puse a ver qué cosas interesantes se podían hacer con toda la cantidad de información que mueve semejante monstruo (sobre todo ahora mismo, con unos 15000 usuarios activos y unas 160000 selecciones de series hechas por los usuarios).

Así que me puse manos a la obra y monté una especie de sistema que generase recomendaciones para series. Y menuda basura.

La idea es de generar una lista de series “similares” a las dadas anteriorente. Técnicamente, es poesía. Sin embargo soy incapaz de entender código un mes después de escribirlo (eso es un problemón), y los resultados no son tan precisos como deberían. Al fin y al cabo, funciona pero con sus detalles.

El principio técnico es … algo extraño. Primero se seleccionan los usuarios que ven alguna de las series seleccionadas. Esta lista se procesa de manera a posicionar a los usuarios que mayores coincidencias tienen, y calcular su afinidad. Por dar un ejemplo: si un usuario ve las 5 series que yo he seleccionado más una más, esa serie (y por lo tanto, ese usuario, que pasará con mayor peso a la segunda parte) será mucho más importante que cualquier otra serie que sea vista por un usuario que vea mis 5 series y otras 15 más.

Después de atribuir los puntos a los usuarios, y los bonus a las series, se aplican también una serie de penalizaciones (por ejemplo, en el caso de que un usuario vea mis 5 series escogidas más una, si esa serie es por ejemplo la más vista, no va a tener prácticamente peso en el cálculo final, o de manera opuesta va a tener mucho más peso si se trata de una serie en la larga cola que tiene especial relevancia entre los usuarios con gustos similares a los míos).

Pero ahí vuelve a destacarse otro gran problema: la larga cola. En las series, por ejemplo, Nurse Jackie es reciente y podría cubrir ciertas recomendaciones cuando el usuario por ejemplo ya ve House y Mental. Pero (y por pura estadística), Heroes (que es la serie más suscrita en la plataforma) va a tener mayor relevancia que Nurse Jackie, pese a todos los bonus, aunque sean negativos.

Un método alternativo sería el clustering y k-means (bueno, no voy a hablar demasiado, la explicación técnica induce al suicidio). A parte de que no comprendo la mitad, no contempla de la misma forma la cantidad de suscritos (y después de tantas pruebas puedo decir que algo sí que importa en este caso). El sistema de k-means (a parte de ser horriblemente complicado) se basa en crear “inicios” aleatorios, para crear unas especies de polos (sí, y esto sigue siendo complicado). Y es imprevisible.

Otro problema (y ya de la propia naturaleza del sistema): igual que te puede gustar House, puedes odiar a Mental y Pushing Daisies, y para más inri, estar enganchado a Big Brother. Digno de una muerte dolorosa, sí, pero ocurre… y es que el ser humano… es extraordinario (y en esto no pensé antes).

Hasta aquí, verborrea. Ahora pasemos a lo interesante y triples anidados de listas completamente innecesarios:

  • Diferentes ejemplos de resultados:
    1. House, Mental, Nurse Jackie, Dexter, Bones
      • Fringe
      • Dollhouse
      • Heroes
      • Burn Notice
      • Chuck
      • Lie to me
      • The Mentalist
      • Eureka
      • True Blood
      • Lost
    2. NCIS, CSI: NY, Criminal Minds, Numb3rs, Cold Case
      • CSI
      • CSI: Miami
      • Bones
      • House
      • The Mentalist
      • Fringe
      • Burn Notice
      • Chuck
      • Lie to me
      • Heroes

Las dos “selecciones” son a grandes rasgos de dos temáticas diferentes. La primera, de medicina e investigación criminal, la segunda de investigación criminal y enigmas criminales, por decirlo de alguna forma. Por lo tanto, existe un ‘cruce’ entre las temáticas, aunque sus extremos están bastante alejados. Los elementos en itálica señalan coincidencias en ambas listas y los elementos en negrita señalan a series en el Top 10 de series más suscritas.

Las coincidencias son demasiado abundantes, ya que en ambos casos las series con mayor número de suscriptores ganan por encima de las series que realmente serían buenas sugerencias (por ejemplo, Dollhouse en la primera selección, pienso). Luego, las posibles selecciones (que se encontrarían a los “extremos” de ambas temáticas) en ciertos casos pueden no ser un reflejo de lo que el usuario espera.

El cruce entre las series también se reporta a cualquier otro set de sugerencias. Las series en sí también evolucionan y no siempre mantiene una temática definida (por ejemplo, Lost pasó de ser una serie intrigante a ser una mierda intrigante). En ocasiones los “grupos” de series se solapan entre sí, así que del momento en el cual se escogen series que podrían pertenecer a grupos distintos (Bones, Dexter, NCIS) el resultado de la sugerencia es completamente inútil y sin sentido.

Pero sigamos…

  • El problema técnico:
    1. Lecturas a la base de datos: para calcular absolutamente todo se necesita recurrir a la base de datos, y eso hace una media de 3000 lecturas por recomendación.
    2. Cache: la solución al primer problema sería guardar el set cada lectura en memcache (el sistema de MySQL se revela inútil en estos casos). Sin embargo, debido a que se tratan de consultas muy precisas (y con muchos datos devueltos), por ejemplo, los shows de X usuario, el hit rate es bastante bajo (y a falta de RAM, termina siendo un mal amigo para un sistema como showRSS).
    3. La larga cola: esto sí que es un monstruo, y pura estadística. Cuanto más se ve una serie, más posibilidades hay de que se cuele en las sugerencias, y por mucha penalización que exista, es casi inevitable.
    4. La interfaz: no es realmente un problema técnico, pero si un verdadero marrón, a mitad entre diseño y técnica… por que cuando 150 líneas de JS dejan de funcionar sin motivo aparente bajo Internet Explorer, a uno le entran unos instintos asesinos bastante preocupantes.

A la larga, es muy difícil mantener un proyecto así funcionando. Requiere tener una máquina aislada (aunque se trate de un VPS, de lo contrario un pico de uso o simplemente un capullo abusón reventarían un servidor entero), suficiente RAM como para tener un cache funcional (y no un cache “peligroso”), y un programador que sepa interpretar su propio código (prometo no volver a usar nombres de variables abstractos sin documentar, lo prometo, por mi bien).

¿Y cual es la utilidad real? Posiblemente, ninguna. La información así es interesante para hacer tartitas y barritas, pero no para ayudar a descubrir nuevas cosas…

Concluyendo: Las sugerencias no funcionan… por ahora. Y es que el ser humano es imprevisible (y espero que nadie me pida nunca consejo sobre estos temas, al menos por ahora), por ahora tocará seguir encontrando series a la vieja usanza: amigos, zapping y EZTV.

¿Alguien dijo recomendaciones personalizadas? De moda, e inútil.

Euskal Encounter 17

Y esperando a la 18! Ha estado genial, con montones de conferencias, gente interesante, concursos, noches en vela… :-) … y a diferencia de la Campus Party, no nos hemos asado!

Y a continuación, una chuleta para el año que viene (sí, siempre viene bien y tal):

  • Equipaje: La tienda de campaña, el saco de dormir y eventualmente la esterilla son impepinables… Y unas chanclas no te vendrían mal si piensas ducharte. Y si te da cosa de que te vean el pito, lleva bañador (aunque tampoco es que importe, no?) En cuanto a la maleta, un trolley debería ser más que suficiente. No hay que olvidar que según vayas en metro, tren o simplemente en coche, vas a arrastrar el equipaje tanto en el aparcamiento como dentro y fuera del recinto (y el recinto es enorme!!).
     
  • La tienda de campaña: Yo no llevé ni esterilla ni tienda de campaña, y me arrepiento profundamente. en cualquier caso la esterilla que hace falta, y la tienda de campaña merece mucho la pena. Además, Decathlon vende tiendas de campaña para interior, pequeñas, que se montan solitas (en 2s, dicen). Eso sí, mínimo media hora para volver a montar todo de vuelta.
     
  • Al llegar: La acreditación empieza el día anterior a la inauguración, normalmente al medio día (13h). Es decir, que pese a que la inauguración es al día siguiente por la tarde, la red ya funciona y es posible instalarse sin problemas (como hace la gran mayoría de gente) un día antes. Pese a ello, oficialmente no se considera día de party (aunque todo funciona como un día corriente de party). Y por cierto, esa primera noche pre-party-oficial no apagan las luces, no insistáis!
     
  • Instalarse: En cuanto llegues, instala tu tienda de campaña. Busca un lugar bien situado, eso puede ser por ejemplo relativamente cerca de las duchas (sin inundarte), teniendo los accesos al pabellón del recinto y al exterior a una distancia correcta (evitando ruidos) y en un lugar por el que no pase todo el mundo. Y si tienes miedo por tu equipaje, simplemente llévalo contigo mientras montas la tienda, aunque la seguridad en el recinto es muy buena y está generalmente bien vigilado (tanto servicio de urgencias médicas como vigilancia).
     
  • Las duchas: Las duchas son una mierda. Una-soberana-mierda. Si te duchas, te van a ver el pito, así que si tienes un trauma personal con ello mejor evita limpiarte :-P . Una de las razones por las que viene bien tener una tienda de campaña propia cerca de las duchas, es que puedes llevarte simplemente un bote de jabón, una toalla y unas chanclas, en lugar de tener que cargar con tu ropa de recambio hasta las duchas (o sin cambiarte, da igual), puesto que allí no hay lugar donde dejar tu ropa “a buen recaudo” mientras que te enjabonas y demás cosas.
     
  • Los servicios: Suelen estar ocupados la mayoría del tiempo. Más de uno se ha quedado sin papel higiénico en plena «tarea» (además de que el papel es simplemente horrible). Llevar tu propio papel higiénico no es una idea descabellada (o comprarlo, teniendo en cuenta que hay un Eroski cerca, ahora lo comentaré). Y si no te importa demasiado (como a la mayoría de los mortales), limítate a comprobar que hay papel antes de pasar, y evita dentro de lo posible guarrear todo (visto que hay cola, es posible que el que pase después te vea la cara…). Todos los servicios (o WC) están situados en la parte trasera del pabellón, debajo de las rampas de acceso a la party (la acreditación se sitúa a un nivel superior, y hay escaleras mecánicas y ascensores para bajar al lugar de la party en sí). De cierta forma, el acceso, los servicios y el acceso al pabellón de descanso están en la parte “trasera” del recinto, y por lo tanto las filas AA-AB serían las más alejadas de los servicios, y AA-AB también las más alejadas de las zona de descanso, pero las más cercanas a la zona de pizza, control de escena y pantallas. Así que el sitio también es algo importante!
     
  • Alimentación y aprovisionamiento: En el propio pabellón hay máquinas (pegadas a la zona de acceso y servicios). Las hay de café (de las cuales una a mi me timó dos veces, mierda), de Coca-Cola, de snacks, sandwiches… En la zona opuesta (parte «backstage», tras las pantallas) hay un bar en el que sirven (de 20h a 8h) algunos platos calientes a un precio no demasiado elevado (aunque creo que se exceden bastante en el precio de las bebidas). Y hay un telepizza con pocas y caras ofertas pero con buenas pizzas, en la zona de AA-01 (esquina opuesta al acceso al pabellón de descanso, por cierto).Fuera hay un Eroski, y más lejos un Decathlon, un Media Markt y un par de negocios más. Por cierto, si necesitas un disco duro o algún tipo de hardware a buen precio, pide antes precios en la party y en los propios stands que se suelen instalar (por ejemplo ModPC-Bexitec, tienen hardware a muy buenos precios). Si vas con alguien o simplemente consumes mucho, conviene ir al Eroski el primer o segundo día para “llenar el carro” durante toda la party (simplemente por el ahorro y disponibilidad, merece la pena). Y si tienes por ahí una neverita portátil y no te es un incordio llevarla, puede serte muy útil.
     
  • Ordenadores y red: Si vas a querer llevar dos ordenadores, necesitas un switch. En mi caso llevé dos y de ello me arrepiento bastante, puesto que al final casi no jugué (tenía intención de participar en partidas LAN, pero apenas había y si no, había ya lío con otros temas, es difícil aburrirse!). La red es Gigabit, es decir, que cualquier instalación Fast Ethernet (100mbit), ya sea por una tarjeta de red no-gigabit o un switch que no soporta gigabit, es un desperdicio de recursos… y al intercambiar ficheros por DC++ (Direct Connect), se nota mucho la diferencia! Hay que compartir un mínimo de 2 GB para poder conectarse al DC++, y el programa tiene que hashear antes todos tus archivos, así que merece la pena configurar el DC junto con lo que vas a compartir previamente. La red asigna direcciones IP públicas, y la diferencia de velocidad de navegación en internet (en comparación a un ADSL residencial) no se nota demasiado (salvando algunas diferencias, por ejemplo es prácticamente imposible saturar la conexión para que vaya lenta!). Por cierto, no lleves algún router o volverás sin él, limítate a llevar un switch si realmente lo necesitas, y otra vez más, piensa en reducir tu equipaje al mínimo.
     
  • Concursos: Hay concursos de muchos tipos y con diferentes premios. En algunos como el Hackit se puede participar simplemente por diversión. Un consejo personal: no te cortes, hay muchos concursos, muchos premios, y mucha gente se corta simplemente pensando que no van a llegar a ningún lado… y se equivocan ;-) .
     
  • Último día: Si tienes que volver en tren o si se da el caso, en avión, duerme aunque sea un poco antes (y eso va por retorcida experiencia, el día de la vuelta dormí apenas 2h cuando ya era de día, y de milagro no me quedo allí). También ten un especial cuidado con tus pertenencias, aunque sin exagerar (la seguridad sigue estando muy presente como el resto de días, pero una cámara o un móvil sin dueño no se ven de la misma manera que cualquier otro día).

Demás cosas: posiblemente se me hayan quedado en el tintero, sin que yo sea consciente. Iré añadiendo cosas según se me ocurran :-) , espero que le sea útil a alguien! (A parte de mi, claro)… Y espero veros el año que viene ;-)