Noticias Weblogs Foros Wiki Código

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Sponsors

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin

Picando Código

Mini-truco: Mostrar las tablas en una base de datos de PostgreSQL

Mayo 19th, 2010 - [Enlace local]

PostgreSQL

PostgreSQL

A veces me olvido de esto así que lo anoto acá. Justo estaba trabajando por SSH y quería ver si el deploy había creado correctamente las tablas, y si quedaban tablas de sobra de versiones anteriores.

En la línea de comandos de PostgreSQL (psql), ejecutar este comando:

\dt

Esto lista las tablas de la base de datos en la cual estamos trabajando.

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Arragonán

El asesino del portátil

Mayo 19th, 2010 - [Enlace local]

Cuántas veces me habrá pasado por la cabeza hacer algo así XD

» Leer más, comentarios, etc...

MadeInFlex

Disponible la Adobe AIR 2 Release Candidate

Mayo 19th, 2010 - [Enlace local]

Aunque sabemos que AIR 2 está bajo desarrollo, ya podemos descargar la Adobe AIR 2 Release Candidate. Debemos tener en cuenta de que esta versión está en desarrollo, como hemos dicho, lo que significa que contiene bugs y que aún no implementa la totalidad de sus funcionalidades. Para los que querais probar esta versión, aquí está el link.

» Leer más, comentarios, etc...

MadeInFlex

Cairngorm 3 liberado

Mayo 19th, 2010 - [Enlace local]

Ya podemos anunciar que Cairngorm 3 se ha liberado. La nueva versión de Cairngorm nos aporta mejores best practices para el desarrollo de aplicaciones Flex y AIR. Nos aporta modularidad, IoC y permite agile testing entre otras muchas cosas. Además nos proporciona unas guías, herramientas y librerías para usar en nuestros desarrollos empresariales. Podemos encontrar más información en este link.

» Leer más, comentarios, etc...

programania

Seguridad básica en Apache

Mayo 18th, 2010 - [Enlace local]

¿Cuantas veces habeis os habeis dicho “Anda, otro servidor con debian con PHP x” gracias a un error 404?

Tonterías de este tipo son el primer paso de cualquier hacker, o script kiddie para hacer el mal en vuestras máquinas y aplicaciones, veamos algunas cosas básicas para no estar tan expuestos en nuestro servidor.

En el fichero /etc/apache2/httpd.conf, o en el caso de algunos sabores de debian en el fichero /etc/apache2/conf.d/security tendremos que activar las siguientes directivas:
ServerSignature Off (esta evitará esos piés de página tan chivatos en los errores y listados)
ServerTokens Prod (esta modificará las respuestas HTTP)

Ahora en los ficheros de definición de los directorios del apache /etc/apache2/sites-avaliable/default (o default-ssl), dentro de los tag Directory, configuraremos la siguiente opción:
Options -Indexes (evitará que al poner una / al final de una URL al usuario le salga un listado del contenido del fichero)
Options -FollowSymLinks (evitará que se puedan crear enlaces en los ficheros que forman nuestra aplicación, esto es una precaución mas que interesante que tomar)

Se que no son una gran medida de seguridad, pero siempre he sido un gran defensor de La Teoría de las ventanas rotas, y creo que si a priori un servidor parece cuidado, será respetado, mientras que si ya a priori da la impresión de inseguro, invitará a ser “retado”.


» Leer más, comentarios, etc...

programania

Un proyecto, múltiples dominios con Symfony 1.4 y Propel 1.5

Mayo 18th, 2010 - [Enlace local]

Entre los múltiples saraos en los que me veo envuelto hay uno que obliga a plantear una solución para el contexto que describo en el título: un solo proyecto debe servir varios dominios (en varios idiomas, sea dicho de paso).

No es que sea un problema terrible, pero la elección de una mala solución puede acarrearos más de un quebradero de cabeza, creedme.

En mi caso, tengo un site con 9 dominios (.es, .fr, .it, .de, .pt, .co.uk, .nl y 2 .com) que se puede presentar en 7 idiomas (es, fr, pt, it, nl, de, en), según esté definido en una tabla de relación n a m que prepararemos para el caso.

La manera natural de abordar el problema sería montar un proyecto o una aplicación para cada site en Symfony y luego hacer un poco de magia de rutas, enlaces blandos, virtual hosts y demás cochinadas que funcionar, funcionan, pero que os van a consumir el alma cada vez que tengáis que hacer el más pequeño de los cambios.

Lo suyo, como en todo lo demás en desarrollo, es echarle unas horas de reflexión y análisis y, sobre todo, mirar si alguien ya ha resuelto el problema antes que vosotros. Una de las máximas del desarrollo es:

“Siempre hay alguien más listo que tú, que ha resuelto eso que quieres hacer de una manera mucho más elegante.”

Con esto en mente, he podido encontrar un magnífico artículo que resuelve la parte de los sites desde el punto de vista de Doctrine: Multiple domains for one symfony project, the basics

Yo he seguido las instrucciones del artículo, pero mi proyecto usa Propel 1.5 como ORM, así que no he podido aplicarlo todo a pie juntillas, ya que en Propel no tenemos la clase SiteTable que nuestro autor utiliza como “chuleta” que permitirá a la aplicación saber qué site está manejando en cada momento.

En vez de eso, lo que propongo es recuperar la instancia de la clase Site que corresponda en función de la URL a través de la cual nuestro usuario ha llegado a la aplicación y la guardaré en el contexto para que esté accesible en toda la aplicación mediante:

sfContext::getInstance()->get('site');

Aunque a continuación voy a detallar todo lo relativo a los sites, os recomiendo que antes de seguir leáis el artículo que menciono para entender bien el contexto. Además, si vuestro ORM es Doctrine, podéis saltar directamente a la parte en la que hablo de la gestión de culturas. En el artículo podréis ver con más detalle varios aspectos a tener en cuenta como la configuración del VirtualHost en vuestro servidor web, por ejemplo.

La estructura de datos

  culture:
    _attributes: { phpName: Culture }
    culture_code: { phpName: CultureCode, type: VARCHAR, size: '5', primaryKey: true, required: true }
    name: { phpName: Name, type: VARCHAR, size: '45', required: true }
  site:
    _attributes: { phpName: Site }
    id: { phpName: Id, type: INTEGER, size: '11', primaryKey: true, autoIncrement: true, required: true }
    domain: { phpName: Domain, type: VARCHAR, size: '200', required: true }
    name: { phpName: Name, type: VARCHAR, size: '100', required: true }
    main: { phpName: Main, type: TINYINT, size: '1', required: true, defaultValue: '0' }
  site_has_culture:
    _attributes: { phpName: SiteHasCulture, isCrossRef: true }
    site_id: { phpName: SiteId, type: INTEGER, size: '11', primaryKey: true, required: true, foreignTable: site, foreignReference: id, onDelete: RESTRICT, onUpdate: RESTRICT }
    culture_culture_code: { phpName: CultureCultureCode, type: VARCHAR, size: '5', primaryKey: true, required: true, foreignTable: culture, foreignReference: culture_code, onDelete: RESTRICT, onUpdate: RESTRICT }
    main: { phpName: Main, type: TINYINT, size: '1', required: true, defaultValue: '0' }

Advertencia: Este código YML ha sido obtenido a través de ingenieria inversa, por lo que no sé si la ingeniería directa os dará algún problema o no… yo no lo he probado.

Nótese el atributo isCrossRef en la definición de site_has_culture. Este atributo le indica a Propel que genere métodos que nos abstraen de las relaciones entre site y culture de tal manera que trabajemos con ellas como si fueran relaciones 1 a n. Propel se encargará de mantener las filas de la tabla relación para nosotros.

El truco del almendruco: Eventos

Symfony incorpora un motor de eventos magnífico. Estoy preparando un artículo que trata este asunto, pero mientras tanto, os recomiendo que os empapéis bien sobre esto en el blog de Symfony.

Lo que vamos a hacer es escuchar varios eventos de manera que:

  1. Deduciremos el site que tenemos que usar en función del dominio que haya usado nuestro usuario
  2. Estableceremos la cultura por defecto asignada al site, según esté definido en la tabla de relación site > culture

Para ello, el lugar idóneo es la clase responsable de la configuración del proyecto:

class ProjectConfiguration extends sfProjectConfiguration {
	public function setup() {
		$this->enablePlugins('sfPropel15Plugin');
		$this->enablePlugins('sfGuardPlugin');
 
		// Listener setup
		$this->dispatcher->connect('context.load_factories', array($this, 'detectSite'));
		$this->dispatcher->connect('site.selected', array($this, 'setCultureBySite'));
	}
 
	/**
	 * Detecta el site actual en base a la url
	 * Fallback al site principal (main = 1 in database) si no
	 * encontramos uno que valga.
	 *
	 * @param sfEvent $event
	 */
	public function detectSite(sfEvent $event) {
		$domain = sfContext::getInstance()->getRequest()->getHost();
		$site = SiteQuery::create()->findOneByDomain($domain);
		if (!($site instanceof Site)) {
			$site = SiteQuery::create()->findOneByMain(1);
			$this->dispatcher->notify(new sfEvent($site, 'site.main_fallback'));
		}
		// TODO: Lanzar excepción si no recuperamos ningun Site (no hay main)
		$this->dispatcher->notify(new sfEvent($site, 'site.selected'));
		sfContext::getInstance()->set('site', $site);
	}
 
	/**
	 * Establece la cultura en sesión para todo lo relativo a I18N
	 * en función del site que se esté manejando, subject del evento
	 *
	 * @param sfEvent $event
	 */
	public function setCultureBySite(sfEvent $event) {
		$site = $event->getSubject();
		/* @var site Site */
		$criteria = new Criteria();
		$criteria->add(SiteHasCulturePeer::MAIN, true);
		$culture = $site->getCultures($criteria)->getFirst();
		sfContext::getInstance()->getUser()->setCulture($culture->getCultureCode());
		$this->dispatcher->notify(new sfEvent($culture, 'culture.changed'));
	}
}

Advertencia: Estoy seguro que el Criteria que instancio seguro que se puede evitar por medio del nuevo sistema de Query de Propel 1.5, pero aun no lo manejo suficientemente bien, por lo que he tirado por la calle del medio, como podéis ver :)

Por partes. En el método setup() preparamos dos listeners vinculados a los eventos context.load_factories y site.selected:

$this->dispatcher->connect('context.load_factories', array($this, 'detectSite'));
$this->dispatcher->connect('site.selected', array($this, 'setCultureBySite'));

El primer evento lo lanza Symfony. Elegimos ese evento de entre los que se disparan a lo largo de la carga de la aplicación porque queremos garantizar que tenemos acceso a la base de datos. El segundo evento es lanzado por el método detectSite() para avisar a un posible listener que ya se ha seleccionado el Site con el que vamos a trabajar.

Los métodos que hemos añadido a la clase ProjectConfiguration son bastante sencillos de leer. El primero busca un Site con el domain que recuperamos del objeto Request y si no encuentra ninguno tira del que tenga el campo main fijado a 1. Una vez obtenida la instancia de Site, la guarda en el Contexto y listo.

Dicho método también lanza un evento site.main_fallback (que actualmente ignoramos) cuando se tira del Site principal. Más vale que “zozobre que zofalte”, así que dejamos ese evento puesto por si queremos hacer algo especial en el futuro con él.

El segundo método recupera la instancia de Site que es el sujeto del Evento lanzado y obtiene la cultura principal asignada en la tabla de relación. Después activa la cultura obtenida en el objeto sfUser y ya está.

Aquí lo interesante es ver cómo obtenemos la colección de Cultures a partir de la instancia de Site como si se tratara de una relación 1 a n, cuando en realidad Propel se pega con una tabla de relación n a m:

$culture = $site->getCultures($criteria)->getFirst();

¡Maravilloso!

Resultado

Una vez preparada la clase de configuración del proyecto tal y como describo, nuestra aplicación identificará nuestro site y establecerá la cultura automágicamente cada vez que se cargue una página.

Por supuesto hay muchas cosas que añadir: No queremos resetear la cultura cada vez que se carga la página porque nuestro usuario podrá seleccionar manualmente otra cultura distina o porque está registrado y ha elegido en su perfil que prefiere ver nuestra web en Klingon, por ejemplo.

Lo suyo sería comprobar la existencia de alguna cookie de sesión con este tipo de configuraciones o incluir algún mecanismo que garantice que la configuración automática de cultura se va a realizar una sola vez.

Otra cambio evidente es comprobar que ya tenemos una instancia de Site en memoria antes de realizar las consultas a base de datos. Habría que asegurarse de que solo se “molesta” a la base de datos cuando el $domain es distinto al $site->getDomain().

Para probar cómo funciona solo tenéis que pedirle a Luis que os haga una wonderfulosa clase PHPUnit que lo pruebe o meter esto en una plantilla cualquiera y arrancar el navegador:

¡Índice, nena!
 
Site: get('site')->getDomain()?>
 
Cultura: getCulture()?>

Rellenad varios registros en la tabla de relación para el mismo Site con distintas culturas y comprobad el resultado si cambiáis la fila que contiene el campo main a true.

Piece of cake!


» Leer más, comentarios, etc...

MadeInFlex

Uso del metadata tag Bindable en getters y setters

Mayo 18th, 2010 - [Enlace local]

Flex nos aporta el data binding, un potentísimo mecanismo para reaccionar a los cambios de ciertos tipos de datos. El data binding es una solución ideal para updatear las GUI según cambios en la capa de modelo de datos. Por esta y otras razones, se considera el data binding una característica muy importante del core de Flex.
En este post vamos a ver el uso de este mecanismo mediante el tag [Bindable] aplicado a los getters de propiedades.

Introducción

Al implementar getters y setters para acceder a una propiedad de un objeto y debemos permitir data binding, hay dos maneras de hacerlo, o lo que es lo mismo, hay gente que lo codifica así:

o gente que lo codifica así:

Un ejemplo de esta última aproximación es el ejemplo que tenemos en las APIs de Flex respecto a la interface IDataRenderer. El ejemplo que nos da la API es el siguiente:

Pero, ¿realmente conocemos la dieferencia entre estas dos formas de implementación? Supongo que muchos sí, pero no está de más que lo expliquemos para los que no.

Explicación

Cuando una propiedad es la fuente de un data binding, Flex copia automáticamente el valor de esta propiedad a la destination asignada cuando esta propiedad fuente cambia. Para avisar a Flex que debe hacer esta copia, todos sabemos que debemos usar el metadata tag [Bindable]. Como hemos dicho, este tag tiene dos sintaxis posibles:

[Bindable]
[Bindable(event="eventname")]

¿Què pasa si omitimos el nombre del evento? pues Flex immediatamente lanza un evento llamado propertyChange y de tipo PropertyChangeEvent.

Hemos hablado de propiedades, pero aplicándolo a getters y setters, si definimos un setter, estamos creando una propiedad de sólo escritura, la cual no se puede usar como fuente de una expresión de data binding. En cambio, al definir el getter, creamos una propiedad de sólo lectura, la cual podemos usar como fuente en una expresión de data binding mediante el tag [Bindable].

Entonces si creamos un getter con el tag [Bindable] sin evento, el compilador de Flex generará un evento llamado propertyChange y de tipo PropertyChangeEvent para esta propiedad. Si el valor de esta propiedad no cambia, Flex no lanza el evento para updatear la propiedad.

Por otra parte si codificamos un getter con evento, por ejemplo [Bindable(event="nameChanged")], nosotros seremos los responsables de lanzar este evento, normalmente en el setter de la propiedad y Flex no mirará si el valor de la propiedad ha cambiado.

Hemos dicho que si no se pone el nombre del evento en el tag Bindable, Flex crea un evento de tipo PropertyChangeEvent, la pregunta es, ¿Por qué este evento y no otro?

Pues la respuesta es porque la clase PropertyChangeEvent representa el cambio en una propiedad de un objeto y proporciona información sobre este cambio. Este evento es usado por las clases de tipo collection y es la única forma de notificar a las colecciones de que los datos que contienen han cambiado.

Si analizamos esto, estamos diciendo que si en un objeto declaramos para una propiedad un getter con un tag Bindable con el nombre de un evento, cuando esta propiedad cambie, Flex no lanzará un PropertyChangeEvent. Si este objeto está contenido en una collection, ésta no se enterará.

A continuación muestro unas imágenes de este proyecto, en el cual podemos experimentar esto que acabamos de explicar. Hay dos objetos diferentes que tienen una propiedad llamada name y a la cual accedemos por getters y setters. En una de estas clases, el getter tiene el tag Bindable y la otra el tag Bindable con el nombre del evento nameChanged. Estos dos objetos están contenidos en un ArrayCollection. La aplicación nos permite cambiar el nombre de cualquiera de estos dos elementos. Como vemos en la imagen que sigue, cuando cambiamos el nombre al elemento que tiene el getter sin ningún evento asociado, el ArrayCollection se da cuenta de que éste ha cambiado:

Captura de pantalla 2010-05-14 a las 16.39.52

En cambio, cuando cambiamos el nombre al objeto que tiene el getter con un evento asociado, el ArrayCollection no reconoce cambios:

Captura de pantalla 2010-05-14 a las 16.39.43

Conclusión

es importante tener en cuenta estos dos tipos de data bindings que hemos visto en el artículo debido a la repercusión que puede tener en la aplicación. En el caso de que los objetos estén en collecciones: puede ser que tengamos que esperar cambios de los objetos y que la colección no lo notifique. Entonces revisemos como hemos tratado los Bindings.

» Leer más, comentarios, etc...

Arragonán

SQL con Javascript: Web SQL Database

Mayo 18th, 2010 - [Enlace local]

Como supongo que muchos ya sabréis, una especificación de HTML5 es Web SQL Database para persirtir datos en una base de datos relacional embebidos en el navegador web(la otra alternativa es Web Storage, para persistir datos como clave valor). Esto puede tener muchas aplicaciones, en mi caso lo he utilizado para implementar el sistema de favoritos de DNDzgz.

Cuando pretendamos sacar partido de las nuevas características de HTML5 debemos tener en cuenta que cada navegador puede soportar sólo algunas especificaciones, no es un todo o nada, por lo que lo primero que deberemos hacer es comprobar que soporta la especificación que queremos usar, por ejemplo:

function supports_local_database() {
return !!window.openDatabase;
}

Si existe openDatabase, crearemos la conexión a la base de datos:


db = openDatabase('dndzgz', '1.0', 'DNDzgz', 65536);

Una vez abierta la conexión, podremos ejecutar cualquier tipo de query SQL(compatible con SQLite), dentro de una transacción. Por ejemplo crear una tabla:

db.transaction(
function(transaction) {
transaction.executeSql(
'CREATE TABLE IF NOT EXISTS favorites ' +
' (id INTEGER NOT NULL, ' +
' service VARCHAR(255) NOT NULL, ' +
' date DATE NOT NULL,' +
' name VARCHAR(255) NOT NULL, ' +
' latitude REAL NOT NULL, ' +
' longitude REAL NOT NULL, ' +
' PRIMARY KEY (id,service));'
);
}
);

Insertar datos:

db.transaction(
function(transaction) {
transaction.executeSql(
'INSERT INTO favorites (id, service, date, name, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?);',
[id, service, new Date(), name, latitude, longitude],
callBack,
errorCallBack
);
}
);

Eliminar datos:
db.transaction(
function(transaction) {
transaction.executeSql('DELETE FROM favorites WHERE id=? AND service=?;',
[id,service], null, errorCallBack);
}
);

Y por supuesto mostrarlos:

db.readTransaction(
function(transaction) {
transaction.executeSql(
'Select * from favorites;', [],
function(transaction, result){
for (var i=0; i < result.rows.length; i++) {
var row = result.rows.item(i);
alert(row.name);
alert(row.service);
}
},
errorCallBack
);
}
);

Como podéis ver, a executeSql se le pasa primero la query, seguidamente un array con los valores de los argumentos de la query, y finalmente una función de callback y otra de callback para el caso de que existan errores. Y existen dos tipos de transacciones: transaction y readTransaction, la primera es de lectura escritura, mientras que la segunda es de sólo lectura.

En fin, supongo que a otros también os pasará lo mismo, resulta bastante raro estar tirando queries SQL desde javascript. Pero puede resultar útil para muchos casos, empezando por descargar de responsabilidades y carga al lado servidor.

» Leer más, comentarios, etc...

Variable not found

Consejos imprescindibles por si algo falla

Mayo 17th, 2010 - [Enlace local]

Desarrolladores tatuados ¡Ah, cómo nos parecemos los desarrolladores! Independientemente de la tecnología, el tipo de aplicación, o el cliente, parece que llevamos tatuados de serie unos comportamientos que repetimos una y otra vez ante escenarios similares.



Debe ser por eso que me divierten y me identifico tanto con los posts que enumeran estos hábitos tan comunes, como el clásico las “20 respuestas más utilizadas por los desarrolladores cuando sus programas no funcionan”, que pulula por la red desde hace muchos años y del que he encontrado versiones en todos los idiomas, por lo que soy absolutamente incapaz de citar la fuente exacta.



El hecho es que justo en el momento en que se nos informa de que algo ha fallado en una de nuestras aplicaciones, el cerebro comienza a trabajar aceleradamente en busca de una excusa explicación, por lo que he pensado que combinando esta lista de frases con unos sabios consejos, seguro que puedo ayudar a más de uno a evitar las tensiones derivadas de los errores en programación.



Y es que, al final, seguro que todos acabamos diciendo aproximadamente lo mismo…



20. “¡Qué raro!”. Primera regla del desarrollador experimentado: mostrar asombro cuando algo falla. Alguien que no se extrañe de la aparición de un error puede aparentar ser bastante mediocre. Hay quien incluso, para acentuar más aún su profesionalidad, añade “¡Imposible!”.



19. “Nunca había pasado antes”. Por si no queda claro con el conjunto de exclamaciones anteriores, apostillar con esta declaración deja claro que os encontráis ante algo insólito. Esto, además, puede ser útil para despertar el espíritu aventurero en tu interlocutor, y hacerlo partícipe en el enfrentamiento a lo desconocido que estáis a punto de comenzar.



18. “Ayer funcionaba”. Busca un soporte sólido para aferrarte, una referencia fiable como esa. Decir que ayer funcionaba es una afirmación ideal: difícil de probar, y si estás ante alguien cándido e inocente, será suficiente para convencerlo de que el error se ha generado hoy mismo, como por arte de magia.



17. “¿Cómo es posible?”. Otra oportunidad para demostrar tu asombro, que además surte mayor efecto si lo sigues con una explicación que tu interlocutor no sea capaz de entender: “cuando I,J,K y no M,N,L es imposible que X,Y,Z”.



16. “Debe ser un problema hardware”. Segunda regla del desarrollador experimentado: si la cosa se complica, puedes ir abriendo el camino a nuevas posibilidades, alejadas de nuestra responsabilidad. Nada podemos hacer contra fallos en la máquina, nosotros sólo entendemos de software. De hecho, si somos incapaces de dar con el problema (y por tanto incapaces de solucionarlo), echar las culpas al metal es una vía de salida de lo más airosa.



¡Te vas a tragar la pantalla! 15. “¿Qué hiciste mal para que fallara?”. Duda siempre de la lucidez del usuario. Si lo acusas de ser un zoquete tendrá que dedicar su tiempo de proceso a defender su postura, y no a vapulearte como te mereces.



14. “Hay algo raro en tus datos”. Es una variación más ligera del caso anterior; estás descargando responsabilidad sobre el usuario, aunque de forma menos agresiva, pues no es un ataque directo a su persona, sino a los datos que utiliza. Esta fórmula puede ser útil y prudente si, por ejemplo, el usuario del sistema es tu jefe.



13. “¡No he tocado ese módulo en semanas!”. Eso es, deja claro que tú no has tocado nada, y que por tanto la responsabilidad no es tuya. Si el módulo funcionaba hace un mes y no has tocado nada, está claro que la culpa el del usuario, del entorno, o del propio desgaste, como las ruedas de un coche.



12. “Debes estar utilizando una versión incorrecta”. Esta es una técnica avanzada para aplicar una vez te has percatado, en silencio claro está, de que había un error tuyo en tu aplicación. Acusa al usuario de utilizar una versión antigua del software, y suminístrale la versión correcta, en la que obviamente ya has parcheado el error.



11. “Se trata sólo de una casualidad”. Utiliza el azar como causa de los problemas; es impredecible, incontrolable y misterioso, una cortina de humo ideal para esconder nuestras meteduras de pata.



10. “Uno no puede probarlo todo”. No somos Dioses… quizás estemos muy cerca, pero no lo somos. Esta frase, a utilizar sólo en casos señalados, puede mostrar humildad y apelar a la bondad del interlocutor para disminuir la tensión. O también, puede servir para arremeter contra tu organización, la falta de recursos, de tiempo, etc., que el usuario empatizará y lamentará contigo.



9. “Eso no puede ser la causa del problema”. Sé tajante; aunque tenga razón, no permitas que un usuario listillo te revele el motivo exacto por el que ha fallado tu aplicación, pues nadie la conoce mejor que tú. Si después de usar esta frase confirmas que la causa era la apuntada por este individuo, no lo reconozcas, y utiliza verborrea técnica para desviar la atención a otras causas.



8. “Eso funciona, aunque no lo he probado”. Un desarrollador profesional no necesita probar las cosas para saber que funcionan, eso es cosa de débiles e inseguros. Una afirmación tan rotunda desequilibrará al interlocutor y lo hará dudar de su criterio a la hora de detectar el error, momento que puedes aprovechar para rematar con cualquier otra frase.



7. “Alguien debe haber cambiado mi código”. Otra regla de oro del desarrollador, aunque compartida con otras profesiones: échale las culpas a otro. Una vez demostrado que hay un fallo y que no puedes hacer responsable al usuario, no hay nada mejor que echar la culpa a los compañeros. Y si crees que no es ético, recuerda: ellos también lo harían.



6. “¿Has comprobado si tienes un virus?”. Los virus, esos seres misteriosos que sólo podemos comprender los iniciados y de los que todo el mundo ha oído historias terribles, son también firmes candidatos a salvarnos el trasero cuando la cosa se está poniendo peligrosa. Dado que la respuesta a esta pregunta casi siempre va a ser negativa, estamos ganando tiempo e introduciendo un factor externo sobre el que descargar las culpas, haciendo al usuario responsable por su incompetencia para mantener su equipo limpio.



BSOD 5. “Bueno, no funciona, pero mola, ¿eh?”. Ante una encerrona, apela al sentido del humor de tu interlocutor. Intenta detectar algún aspecto positivo del desastre, y preséntalo de forma atractiva para el usuario. ¿Un proceso tarda demasiado? Así tienes más tiempo para estirar los músculos; ¿La aplicación se cierra violentamente? Así puedes apagar antes el equipo e irte a casa; ¿Una BSOD? Fíjate qué fondo de pantalla azul eléctrico tan espectacular te pone el programa cuando falla.



4. “No puedes usar esa versión en tu sistema” Cuando el número de errores sea tan alto que pueda poner en peligro tu credibilidad como profesional, no reconozcas haberlos cometido; utiliza motivos estructurales como el hardware, los virus, o el versionado de sistemas para hacerles ver que eres totalmente inocente.



3. “¿Por qué quieres hacerlo así?” Una posibilidad muy socorrida es a veces instruir al usuario para que realice las tareas justo de la forma en que la aplicación funciona correctamente, censurándole rápida y tajantemente los intentos de salirse del camino marcado. A veces es más fácil adaptar el usuario a la aplicación que viceversa.



2. “¿Dónde estabas cuando el programa falló?” Ideal para aplicaciones que funcionan como procesos por lotes, o para intentar culpar al usuario de su ausencia en un momento vital como en el que se produjo el problema. Sobre todo si sabemos que el usuario es tendente a despistarse, esta puede ser un arma realmente interesante.



1. “No es un error, es que el programa funciona así”. Aprovecha la delgada línea que separa un bug de una feature. Esta técnica avanzada te permitirá desviar la atención hacia las personas que decidieron las funcionalidades, recogieron los requisitos, o validaron el software, pero nunca hacia el desarrollador que simplemente siguió las instrucciones.



¡En mi máquina funciona!Y por último, la frase más utilizada sin duda por los desarrolladores:



0. “¡En mi máquina funciona!” Desconcierta al interlocutor, y queda como debes, por encima de todos. El software funciona en entornos controlados como el tuyo, propios de un experto, donde todo está perfectamente en orden y lejos del alcance de las manazas del usuario final.



Eso sí, hay que estar preparados para una respuesta como la siguiente:

"¡No me importa si funciona en tu máquina!

¡No estamos vendiendo tu máquina!"

-- Vidiu Platon
Publicado en: Variable not found



» Leer más, comentarios, etc...

Ingenieria de Software / Software Engineering / Project Management

Resumen Convergence 2010

Mayo 17th, 2010 - [Enlace local]

Me resulto muy grata la experiencia vivida en Convergence 2010, principal evento de Microsoft para sus aplicaciones empresariales Dynamics, aunque es un evento que se aprovecha para tejer negocios con otras empresas o clientes resalto los siguientes puntos:

1) Uno de los mensajes principales fue Cloud Computing mucha de la estrategia estará dirigida hacia la nube

2) Las redes sociales parte importante del MKT para CRM

3) Un acelerador importante que se libero es Customer Care para Call Centers

4) La presentación que mas me agrado fué de SureStep y mas por la exposición de un cliente quien resaltaba puntos importantes de la metodología y que daba tips de como abortar un proyecto de CRM

» Leer más, comentarios, etc...

MadeInFlex

¿Otro ataque contra la plataforma Flash?

Mayo 17th, 2010 - [Enlace local]

Después del revuelo que generó Steve Jobs con su publicación en la que se posicionaba en contra de Flash, han aprecido posts diciendo que es ahora Microsoft quien también se posiciona en contra de Flash. Se ha propagado por la red el rumor o noticia de que la próxima versión de su browser, el IE9, tampoco reproducirá Flash.

Las noticias se pueden resumir diciendo que Microsoft cree que el futuro de la web es HTML5 y que IE9 solo reproducirá H.264. Puede parecer una alianza con Apple para luchar contra Adobe, Dean Hachamovitch, Manager General de Internet Explorer, dice que la mayoría de players de vídeos de la web están hechos con Flash y afirma que esa plataforma tiene problemas de fiabilidad, seguridad y rendimiento. Por otro lado también dice que Microsoft colabora continuamente con Adobe para mejorar estos puntos y hacer intercambio de concimientos y aclara en este post que seguirá ofreciendo soporte a Flash mediante plug-in, como ha ido haciendo hasta ahora.

Diferentes articulistas dicen que estas declaraciones de Microsoft y Apple viene dadas por el hecho de que estas empresas tienen sus propias tecnologías para reproducir video y que no han sido capaces de quitarle la autoridad a Flash.

por otro lado, me ha dolido leer ciertas entradas contra la plataforma Flash, como por ejemplo una en la que, en uno de sus párrafos, decía lo siguiente: No me importaría ver a Flash desaparecer. Sólo hay dos cosas por las que veo que se use actualmente: renderizar video y dibujar líneas y ambas cosas se pueden conseguir facilmente con HTML 5. También decía el mismo artículo que si Adobe quiere permanecer, deberá mejorar y no dormirse para corregir sus puntos flacos.

Veremos como evoluciona todo esto y esperemos que la plataforma Flash no salga herida de esta guerra en la que se ha visto envuelta.

» Leer más, comentarios, etc...

Picando Código

ArchLinux 2009.08 con KDE 4.4.3

Mayo 16th, 2010 - [Enlace local]

Ya estoy totalmente instalado en mi nuevo ArchLinux. Como verán en el blog, me tiene bastante entusiasmado (este es el cuarto post seguido sobre ArchLinux).

Siguiendo los manuales en la wiki de Arch, ya tengo audio, video, entorno de escritorio, y todo lo que pueda necesitar para usar la computadora.  Algo interesante es que puedo usar versiones más actuales del software, y un paquete de software importante es KDE 4.4. En Debian, hasta ahora, venía usando KDE 4.3, sin poder aprovechar las ventajas de la última versión. Como con cada versión, KDE sigue evolucionando. Captura obligada:

ArchLinux 2009.08 con KDE 4.4.3

ArchLinux 2009.08 con KDE 4.4.3

En cuanto al sistema en general, lo encuentro bastante rápido. Una ventaja importante es que no ha instalado nada que no le haya pedido. Aprendí bastante -aunque tal vez no tanto como hubiera esperado- durante el proceso de instalación. Esto puede querer decir que he aprendido mucho en este tiempo, o que realmente no era para tanto. De todas formas, si bien toma trabajo, es simple. Cumple la premisa de ser: Una distribución liviana y flexible que trata de mantenerlo simple:

Confiar en los GUIs para construir y configurar un sistema termina por dañar al usuario. Es por esto que el usuario necesitara conocer todo lo que los GUIs ocultan y llevar a cabo las configuraciones de forma manual.

Me encanta esa filosofía, y estoy completamente de acuerdo.

Faltan unos días de uso para poder llegar a una conclusión definitiva, si me quedo en Arch o no. Esta computadora mantiene su partición con Debian, a la que no he vuelto desde hace un rato.

Ya comentaré al respecto…

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Picando Código

ArchLinux: Setting Consoles to UTF-8 mode [BUSY] se tranca…

Mayo 16th, 2010 - [Enlace local]

ArchLinux

ArchLinux

Un problemita que me encontré a la hora de instalar ArchLinux:

El sistema base recién instalado, logro bootear en ArchLinux. Empieza a iniciar el sistema, pero se queda trancado en el siguiente mensaje:

Setting Consoles to UTF-8 mode    [BUSY]

En el archivo /etc/rc.conf está la configuración del locale de ArchLinux. Por defecto, estaba escrita la configuración de la instalación: “en_US.UTF-8″. Por alguna razón esto no funciona, ya que la computadora quedaba totalmente trancada.

Sin ánimos de dejarme vencer, teniendo el sistema instalado, decidí buscar en internet. Si bien encontré varios casos en los que se da este problema, ninguno fue suficientemente específico como para poder arreglarlo.

“Parchié el problema”, editando el archivo /etc/rc.conf. Con el comando locale -a, el sistema me mostró los locale disponibles. Uno de ellos era “en_US.utf8″, así que intenté con “LOCALE=”en_US.utf8″ y tampoco hubo caso. Aparentemente es algún problema con utf 8 en mi computadora/instalación. Al final borré la parte de UTF-8 y dejé simplemente “en_US”, y el problema se resolvió.

Es una solución temporal, mientras fui configurando otras cosas del sistema.

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Picando Código

Doble booteo: Debian GNU/Linux y ArchLinux

Mayo 16th, 2010 - [Enlace local]

Debian + ArchLinux

Debian + ArchLinux

Durante la instalación de ArchLinux, la última opción es instalar un bootloader. Nos ofrece GRUB, pero ya lo tengo instalado con Debian. Así que en vez de pasar por arriba mi configuración actual de /boot/grub/menu.lst, decido no instalarlo y agregar ArchLinux a mano a la lista de Grub.

Para esto, edité el archivo /boot/grub/menu.lst, y setié los valores de mi nueva instalación de ArchLinux:

title		ArchLinux
root		(hd0,1)
kernel          /boot/vmlinuz26 root=/dev/sda2 ro
initrd          /boot/kernel26.img

El título lo elegimos como nos guste. El “root” depende de la partición donde hayamos instalado Arch. En mi caso tengo Debian en la primer partición y ArchLinux en la segunda.

La opción root -en la línea que empieza con kernel- es la partición donde debe buscar la ruta especificada.

Así que ahora tengo Debian GNU/Linux en /dev/sda1  y ArchLinux en /dev/sda2.

Pueden encontrar más sobre configuraciones de GRUB en la wiki de ArchLinux.

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 6

Mayo 16th, 2010 - [Enlace local]

Estos son los enlaces publicados en Variable not found en Facebook desde el domingo, 09 de mayo de 2010 hasta el domingo, 16 de mayo de 2010. Espero que os resulten interesantes :-)

Y no olvides que, si te interesa, puedes seguir esta información en vivo y en directo desde Variable not found en Facebook, o a través de Twitter.



Publicado en: Variable not found



» Leer más, comentarios, etc...

Picando Código

Aventura: Migrar a ArchLinux

Mayo 14th, 2010 - [Enlace local]

ArchLinux

ArchLinux

Tengo una idea: instalar ArchLinux. Veamos cómo llegué a tal idea. El fin de semana pasado volvió a mí desde Maldonado Hoth, mi computadora de escritorio.

Hoth

Hoth

Hoth, tiene un procesador AMD Athlon X2, mi primer computadora de 64 bits. Por esto, y siendo hardware bastante nuevo, debería “volar” (andar rápido, ser eficiente, etc.). Sin embargo, no ha sido así. Desde un principio, instalé Debian Testing y usé KDE 4. Tuve, por ejemplo, que desactivar los efectos de escritorio para poder trabajar mejor. Estos ocasionaban mucha lentitud en la interacción con las aplicaciones. Incluso notaba que su rendimiento era más lento que Dagobah, mi computadora portátil (un Dual Core con 2GB de Ram).

De todas formas esto viene solo a forma de comentario, ya que no fue la razón por la que decidí probar ArchLinux. En primer lugar, he aprendido mucho sobre Debian y me siento muy cómodo usándolo. Por esto, considero que estoy aprendiendo muy poco, ya que me encuentro en la “Zona de confort”. Esto es bueno, puedo realizar mi trabajo tranquilo sin preocuparme por la computadora. Pero a su vez, no estoy aprendiendo mucho en lo que respecta al uso del sistema operativo.

Inconforme con esta situación, y decidido a aprender más, voy a usar ArchLinux. Mi primer experiencia con esta distro fue a principios de 2009, donde probé y comenté sobre ArchLinux en mi vieja laptop. En aquel momento el aprendizaje fue también la razón por la que migré. Sin embargo, al haber sido instalada en una máquina secundaria, la prueba no llegó a profundizarse, así que no podía siquiera considerarme “usuario de ArchLinux”. No pasé mucho más de la instalación y configuración inicial.

Además, por lo que he visto en la comunidad aparentemente ArchLinux resulta una evolución natural desde Debian. Es una teoría que vengo craneando, aparentemente gran parte de los usuarios de Arch caen desde Debian. ¿Serán las mismas razones que yo? Debian requiere de cierto nivel técnico para aprovecharlo. Pero ArchLinux va un paso más adelante.

Bien, me convencí que la mejor forma de autodenominarme “usuario ArchLinux” con autoridad era instalándolo en una computadora de uso diario, por lo tanto obligándome a configurarlo y usarlo. Así que descargué ArchLinux en una imagen para USB booteable, y procedí a instalarlo.

Booteo ArchLinux desde USB

Booteo ArchLinux desde USB

Mientras escribo este post, se están descargando los paquetes necesarios para instalar el sistema base. Después de eso vendrá la configuración del sistema (ahí entra el aprendizaje) y la instalación de entorno gráfico, etc. Mantuve una partición con Debian por las dudas que me arrepienta, pero me voy a obligar a darle una buena oportunidad. Además no está mal poder probar los paquetes de último momento que caracterizan a ArchLinux.

El nerd dentro mío no puede evitar sentir todo este proceso como algún tipo de aventura…

Ya comentaré más adelante como sigue.

La imagen del planeta Hoth corresponde a Afiches minimalistas de la galaxia de Star Wars.

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Picando Código

Abrir archivos PSD CMYK con GIMP

Mayo 13th, 2010 - [Enlace local]

GIMP

GIMP

Recientemente me he estado involucrando un poco en el mundo del diseño gráfico. Tanto en el cambio de imagen de Picando Código como en algunos trabajos por mi cuenta.

Mi programa preferido a la hora de diseñar, desde hace varios años, ha sido GIMP. Si bien se supone que no es tan potente como otros programas de diseño, para lo que sé y necesito hacer, generalmente es más que suficiente.

Hoy me inspiré y decidí rediseñar e implementar algunas ideas en el sitio de Entropía Records. Para esto, tuve que recurrir a unos archivos PSD, el formato estándard de Adobe PhotoShop. La mayoría de los diseñadores utiliza software privativo de Adobe y Corel, que manejan sus formatos propios de archivos, a pesar de haber estándares.

Gimp hace un buen trabajo abriendo archivos PSD. Mi último trabajo freelance constó de pasar un PSD a tema de WordPress (pueden contactarme por presupuesto :) ), y pude abrirlo sin problemas con Gimp, viendo cada una de las capas y demás.

El problema está cuando el archivo está en el modelo de colores CMYK. Al intentar abrir un archivo PSD CMYK con Gimp, obtuve este error:

Error loading PSD file: Unsupported color mode: CMYK

Si bien sé que existe un plugin para GIMP que le permite usar CMYK, no me aseguraba que pudiera usar el archivo PSD. Por eso, decidí buscar algo que permitiera convertir el archivo a algo más estándard que pudiera usar. Así fue que me encontré con el blog La CromoSaturación y el Iris donde publicaron una solución al problema: PSD2 Conversor de archivos PSD (CMYK) de Photoshop a un estandar libre (RGB).

La solución es usar ImageMagick, particularmente la aplicación Convert. Esta permite convertir el PSD con todas sus capas a varias imágenes o un archivo Tif con todas las capas correspondientes:

convert -depth 8 -colorspace RGB original.psd salida.tif

Pueden leer más detalles al respecto en la entrada original. Simplemente quería compartir la solución y agradecer a Xavier Araque por publicarla en su momento en su blog. Pasen a leer el resto de la entrada ahí, y vean también su colección de scripts y plugins para Gimp.

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Picando Código

Sábado 15 de Mayo: encuentro ceibalJAM! 7

Mayo 13th, 2010 - [Enlace local]

Difundo esta información del grupo Ceibal Jam, desarrolladores de actividades para las queridas XO (o “ceibalitas” como las conocemos cariñosamente).

¡Entrá a la cancha! ¡Todos podemos colaborar en el desarrollo de software para las ceibalitas!

Por eso organizamos el séptimo encuentro ceibalJAM, un espacio para aprender, compartir conocimiento y desarrollar actividades didácticas, útil para las ceibalitas del país y, por qué no, del mundo.

ceibalJAM7

ceibalJAM7

En esta ocasión habrá propuestas para un público diverso, desde docentes y diseñadores gráficos interesados en elaborar contenidos educativos hasta desarrolladores experientes que busquen crear juegos, pasando por talleres de programación a distintos niveles.

El encuentro transcurrirá en 5 ejes temáticos:

En definitiva, el encuentro ceibalJAM servirá una vez más para trabajar, aprender y generar productos. Un espacio para desarrollar el conocimiento y la creatividad, contribuyendo con la educación uruguaya.

FORMULARIO DE INSCRIPCIÓN

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Picando Código

Extensión del paquete independiente humilde de Juegos – liberan el código

Mayo 11th, 2010 - [Enlace local]

¡Libertad!

¡Libertad!

Si no lo han hecho, pueden leer sobre “The Humble Indie Bundle en: Paquete independiente humilde: Juegos multiplataforma al precio que elijas

En un evento que creo podría definirse como histórico, Wolfire Games anunció la “extensión open source” de la promoción Humble Indie Bundle. Traducción libre a continuación:

Actualización humilde: extensión open source (11/05/10)

El experimento Humble Indie Bundle ha sido un éxito masivo más allá de nuestras más locas expectativas. Hasta ahora, en apenas poco más de 7 días, 116.059 personas han colaborado con unos increíbles U$S 1.052.877. De esto, los contribuyentes han elegido asignar un 30.98% a la caridad: U$S 326.146 para la Electronic Frontier Foundation y Child’s Play Charity. He creado una página para el desglose total incluyendo las tarifas de tarjeta de crédito en un formato JSON aquí (json).

Ahora es nuestro turno de devolver. Desde el 11/05/10, Aquaria, Gish, Lugaru HD, y Penumbra Overture se comprometen a abrir su código. Estamos preparando los fuentes ahora y los estaremos lanzando lo antes posible. Pasamos la noche anterior preparando Lugaru y está disponible ahora. El código está un poco áspero (no hay proyecto Visual Studio aún, por ejemplo) pero esperamos que con la ayuda de la comunidad podamos hacerlo más accesible para todos rápidamente.

Nota, los juegos serán “free as in ‘free speech’, not as in ‘free beer’” (creo que no es necesario traducir esta frase :) ): ver cada licencia para los detalles completos mientras son lanzados con mucha ilusión esta semana — estén atentos. Es el código subyacente que se hará disponible para todos.

Siéntanse libres de continuar donando a la caridad, a los desarrolladores, o cualquier combinación de esas abajo. Seguiremos distribuyendo paquetes humildes para cualquiera que contribuya.

Creo que se trata de un hecho sin precedentes en la industria de los videojuegos. Es uno de los mercados donde más se cuestiona la liberación del código, ya que los modelos de negocio tradicionales no parecen compatibles con el software libre. Sin embargo, esta empresa independiente ha demostrado que sí se puede.

Con este experimento, lograron recaudar cientos de miles de dólares para financiar futuros proyectos. Sabiendo que ese dinero fue obtenido gracias a la comunidad, la empresa debe basar su modelo de negocios de manera que devuelva a la comunidad de la manera en que lo está haciendo ahora.

Estoy muy contento de haber aportado a este experimento, esta noticia no deja de sorprenderme y alegrarme a la vez. Aquellos que no quisieron donar por tratarse de software privativo ya no tienen excusas ( ;) ), creo que estamos ante un gran paso en una revolución de la industria de los videojuegos (no olvidemos lo de Ryzom).

Los que no hayan comprado todavía su paquete humilde, están a tiempo de hacerlo, todavía pueden ser parte de este evento. Desde Picando Código mi humilde felicitación a Wolfire Games, ¡espero que otras empresas sigan su ejemplo!

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Variable not found

Validación de rangos decimales en cliente y servidor para ASP.NET MVC 2

Mayo 11th, 2010 - [Enlace local]

ASP.NET MVCUna de las mejoras más esperadas de ASP.NET MVC 2 es, sin duda, el sistema integrado de validación del Modelo basado en las anotaciones de datos (Data Annotations). Y aunque la implementación en general es bastante apañada, hay algunos aspectos mejorables, sobre todo cuando intentamos desarrollar aplicaciones en nuestro idioma.


Por ejemplo, existe un curioso comportamiento del juego de herramientas de validación en cliente y servidor en lo relativo a la introducción de decimales en el Modelo. Imaginemos la siguiente entidad de datos, con sus correspondientes anotaciones:



public class Producto
{
  [Required(ErrorMessage="*")]
  public string Nombre { get; set; }
 
  [DisplayName("Peso (Kg.)")]
  [Range(0.1, 10, ErrorMessage="Entre {1} y {2}")]
  [Required(ErrorMessage="*")]
  public double Peso { get; set; }
}


Centrándonos en la propiedad Peso, la intención de sus anotaciones está bastante clara: queremos que sea de introducción obligatoria, y que su valor se encuentre en el rango entre 0,1 y 10 kilogramos.



Creamos ahora un formulario de introducción de datos para dicha entidad utilizando como base el generado por defecto por Visual Studio. El código resumido de la vista es el siguiente:



<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
 
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>   
 
<h2>Create</h2>
<% Html.EnableClientValidation(); %>
 
<% using (Html.BeginForm()) {%>
 
... // Omitido
 
<% } %>
 
</asp:Content>


Si utilizamos exclusivamente la validación en servidor no habrá problema, pero si, como en el código anterior, activamos en ella la validación en cliente, podemos encontrarnos con un curioso y problemático escenario debido a la falta de sincronización entre las culturas en cliente y en servidor.

Sintomatología

Si en el campo Peso introducimos un entero, por ejemplo un “2”, todo funciona correctamente. El validador en cliente dejará pasar el valor, y en servidor se realizará la conversión de dicho valor a double sin problema.



Sin embargo, al intentar introducir un valor no entero como “1,23” comienza la fiesta. Si utilizamos como separador de decimales una coma, el validador en cliente no nos permitirá hacer un submit del formulario, quedándonos atrapados en esta capa:



Problema en cliente al validar un rango double



Si en cambio utilizamos como separador un punto, por ejemplo “2.5”, la validación en cliente considerará que el valor decimal es correcto, y permitirá el envío de los datos del formulario. Sin embargo, el servidor intentará obtener el valor double utilizando el formato asociado a la cultura actual, en la que el punto no es un carácter válido de separación, por lo que decidirá que el estado del Modelo es inválido, y nos enviará de vuelta al formulario:



Problema en servidor al validar un rango double



(Por cierto, hace unas semanas comenté por aquí cómo modificar los mensajes de validación por defecto en ASP.NET MVC 2, como el error mostrado en la captura anterior).



En resumen: no podemos continuar si utilizamos como separador decimal la coma (primer caso), ni tampoco si utilizamos el punto (segundo caso). Literalmente, estamos en un callejón sin salida.

Diagnóstico

El problema se debe básicamente a que los scripts de validación están utilizando únicamente la cultura “en-US”, en la que el carácter de separación decimal es el punto. Es decir, por defecto se utilizan los formatos de fecha y numéricos de la cultura inglesa/americana, y no existe ningún punto en el código de las librerías de scripting MicrosoftAjax o MicrosoftMvcValidation donde se modifiquen estos parámetros.



Sin embargo, el tratamiento en servidor se realiza bajo la cultura definida en el hilo de ejecución actual, en este caso la correspondiente a “es-ES”, en la que las comas son los separadores entre la parte entera y la decimal.



Esto es fácil de comprobar introduciendo al final de la vista:



<p>
  Cultura en servidor:
  <%= System.Threading.Thread.CurrentThread.CurrentCulture.Name %>
</p>
 
<script type="text/javascript">
  alert("Cultura en cliente: " + Sys.CultureInfo.CurrentCulture.name); 
</script>
 La cultura en cliente y servidor son diferentes



Tratamiento

Es posible que haya formas más sencillas para solucionar esta cuestión, pero de momento la única que he encontrado para sincronizar las culturas es forzar en el lado cliente la utilización de las opciones culturales que estén siendo consideradas en servidor.



Para ello, necesitamos asignar durante la inicialización de la página un objeto de tipo CultureInfo a la propiedad Sys.CultureInfo.CurrentCulture. Este objeto contiene los formatos numéricos y de fecha que serán utilizados en las operaciones de conversión llevadas a cabo desde las librerías de scripting Microsoft Ajax, y necesita dicha información durante su instanciación, como en el siguiente ejemplo:



<script type="text/javascript">
  var ci = {
      "name": "es-ES",
      "numberFormat":   {información de formato numérico}, 
      "dateTimeFormat": {información de formato de fecha y hora}
  };
  Sys.CultureInfo.CurrentCulture = Sys.CultureInfo._parse(ci);
</script>


Sin embargo, esto es algo más complejo de lo que podría parecer en un principio. El formato numérico contiene información sobre los separadores de millares, decimales, formas de representar negativos, monedas, dígitos, etc; de la misma forma, respecto a las fechas, es necesario suministrar el formato, nombre de meses, días de la semana, etc. Sin duda, un trabajo demasiado duro para tener que hacerlo a mano.



Por suerte, la representación de los formatos de números y fechas utilizado por las librerías de scripting de Microsoft son idénticas en cliente y servidor, por lo que podemos serializar como JSON los objetos Thread.CurrentThread.CurrentCulture.NumberFormat y Thread.CurrentThread.CurrentCulture.DateTimeFormat y utilizar el resultado para crear el objeto CultureInfo:



<%
  JavaScriptSerializer jss = new JavaScriptSerializer();
  var cultureInfo = Thread.CurrentThread.CurrentCulture;
  string name = cultureInfo.Name;
  string numberFormat = jss.Serialize(cultureInfo.NumberFormat);
  string dateFormat = jss.Serialize(cultureInfo.DateTimeFormat); 
%>
<script type="text/javascript">
  var ci = {
      "name": "<%= name %>",
      "numberFormat":  <%= numberFormat %>,
      "dateTimeFormat": <%= dateFormat %>
  };    
  Sys.CultureInfo.CurrentCulture = Sys.CultureInfo._parse(ci);
</script>


Pero está claro que no tiene demasiado sentido repetir el código anterior a lo largo y ancho de las vistas de edición de datos donde queramos activar la localización. Seguro que podemos mejorar esto… ;-)

Medicina genérica: El helper Html.EnableLocalizedClientValidation()

Vamos a crear un helper que realice por nosotros estas tareas de la forma más sencilla posible.



Html.EnableLocalizedClientValidation() encapsula el comportamiento del helper estándar EnableClientValidation(), y añade los scripts de inicialización de las opciones culturales comentados anteriormente. Su uso será como se muestra a continuación:



<script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="../../Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script> 
<%= Html.EnableLocalizedClientValidation() %>
<h2>Create</h2>
<% using (Html.BeginForm()) { %>
// .. El resto del código de vista


La única diferencia respecto al método habitual es que estamos utilizando una expresión de salida <%= %>, y que el helper invocado es EnableLocalizedClientValidation().



El código del helper es:



using System.Text;
using System.Web.Script.Serialization;
using System.Threading;
 
namespace System.Web.Mvc
{
  public static class Extensions
  {
    public static MvcHtmlString EnableLocalizedClientValidation(this HtmlHelper html)
    {
      // Habilitamos la validación en cliente
      html.EnableClientValidation();
 
      // Obtenemos la información de la cultura actual
      JavaScriptSerializer jss = new JavaScriptSerializer();
      var cultureInfo = Thread.CurrentThread.CurrentCulture;
      string name = cultureInfo.Name;
      string numberFormat = jss.Serialize(cultureInfo.NumberFormat);
      string dateFormat = jss.Serialize(cultureInfo.DateTimeFormat);
 
      // Generamos el código
      StringBuilder sb = new StringBuilder();
      sb.Append("<script type=\"text/javascript\">");
      sb.AppendLine("var ci = {");
      sb.AppendLine("    \"name\": \"" + name + "\",");
      sb.AppendLine("    \"numberFormat\": " + numberFormat + ", ");
      sb.AppendLine("    \"dateTimeFormat\": " + dateFormat);
      sb.AppendLine("};");
      sb.AppendLine("Sys.CultureInfo.CurrentCulture = Sys.CultureInfo._parse(ci);");
      sb.AppendLine("</script>");
      return MvcHtmlString.Create(sb.ToString());
    }
  }
}


Puedes descargar el código fuente desde mi SkyDrive.



Una última anotación: terminando de escribir este post, observo que el gran Phil Haack (PM de ASP.NET MVC) acaba de publicar una entrada comentando el mismo tema, y enfocando la solución desde otra óptica. Una lástima que no lo haya publicado antes, me habría ahorrado el tiempo que me ha llevado esta investigación, aunque, en cualquier caso, ha valido la pena para entender un poco más los entresijos del framework.



Publicado en: Variable not found

Hey, ¡estoy en twitter!



» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

Microsoft Query “2010″

Mayo 11th, 2010 - [Enlace local]

Microsoft Query, también conocido como MSQRY32, MSQUERY o sencillamente MSQRY es una olvidada utilidad que viene incluida con Excel desde la versión 5 de 1993, y por ende, incluido posteriormente desde Office 4.2.

A pesar del nombre del ejecutable, o su innegable herencia de de la versión 1.0 todavía de 16 bits, en Office 2010 se ha actualizado a la versión 14, donde exceptuando un port completo de x64, contiene las mismas funcionalidades de antaño.

Sorprende que una herramienta así, de la que reconozco he hecho uso en determinadas ocasiones del pasado por su simplicidad, siga casi 20 años después sin apenas cambios, y lo que es más importante, todavía distribuyéndose.

» Leer más, comentarios, etc...

PROGRAMANDO EN .NET

Movimiento NoSQL y MongoDB

Mayo 11th, 2010 - [Enlace local]

Os dejo un interesante artículo de Ted Neward sobre MongoDB:Going NoSQL with MongoDBY sobre dicho artículo, una reflexión: ¿Consideráis el movimiento NoSQL como un paso adelante o un paso atrás?Yo lo veo más como algo que cubre una necesidad. No siempre necesitaremos una base de SGDB como SQL Server, Oracle o MySQL, de la que escasamente vamos a aprovechar un 10 o 20% de sus funcionalidades. Así

» Leer más, comentarios, etc...

Picando Código

Jugando Spore en la vida real

Mayo 11th, 2010 - [Enlace local]

Como el videojuego Spore solo puede jugarse en un sistema operativo privativo, y trae montones de DRM, decidí jugar Spore por mi cuenta en la vida real:

Spore en la vida real

Spore en la vida real

¡Tomá esa Will Wright!

De Wikipedia:
Spore es un videojuego de simulación de vida y estrategia para Microsoft Windows y Mac diseñado por Will Wright que simula la evolución de una especie desde las etapas más primitivas (seres unicelulares) hasta la colonización de la galaxia por parte del ser evolucionado.

Yo no simulé, ¡permití que se generara vida! Pero no los dejé llegar a la colonización de la galaxia…

(Foto sacada de algo en mi heladera que en otra vida fue un calabazín y es ahora una colonia en expansión)

Ya había hecho un experimento parecido con Pablo en:
Cafetera que da vida

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Variable not found

Cuatro años desde que desapareció la variable

Mayo 10th, 2010 - [Enlace local]

¡Cuatro años de variablenotfound.com!Mayo de 2006. Mucho ha llovido desde entonces (y sobre todo este año ;-)). Windows XP era el rey del escritorio, y a pesar de sus inconvenientes, navegábamos con el hoy denostado Internet Explorer 6; Visual Studio 2005 había aparecido recientemente, y comenzábamos a crear aplicaciones para .NET 2.0… ¡ah, qué tiempos!



El pasado 8 de mayo volvimos a celebrar el aniversario de la publicación del primer post en Variable Not Found, ese blog que comenzó tímidamente hace ya cuatro años, con una declaración de intenciones como la siguiente:

Pretendo firmemente, y suelo ser bastante tenaz en mis propósitos, que este diario recoja todo aquello que me llame la atención y mis reflexiones relativas a la tecnología en general, y al mundo del desarrollo de software en particular.
Con mayor o menor frecuencia dependiendo del tiempo libre disponible en cada momento, desde esa fecha he ido publicando por aquí todo aquello que he considerado que podía interesar a alguien más que a un servidor, probablemente unas veces con más acierto que otras, pero, en cualquier caso, siempre con el mismo entusiasmo que el primer día.



Como en otras ocasiones, aprovecho para resumir los distintos periodos por los que hemos ido pasando desde aquél momento.

Estudiemos ahora en profundidad el año que acaba de finalizar:



Año 4: la variable social (mayo 2009-mayo 2010)



Durante este último año el número de visitantes ha continuado en la misma línea de estabilidad ya lograda en el periodo anterior, sin grandes sobresaltos. Los principales indicadores son:

El gran cambio introducido durante este periodo ha sido la inclusión de la componente social, tan al alza en estos tiempos. El pasado mes de octubre creé Variable not found en Facebook, que cuenta ya con más de cien amigos, y que esperaba sirviera como canal bidireccional de  comunicación con el otro lado. Aunque en la práctica todavía no ha sido así, y muy pocos miembros participan activamente, sí que es cierto que ofrece más canales para la distribución de contenidos y, seguro que algún día, para la comunicación entre nosotros.



En la actualidad utilizo Facebook para registrar enlaces a artículos que encuentro cada día y que me parecen interesantes. Relación Facebook/Twitter/BlogDe hecho, también los publico en el blog en las entradas categorizadas “Enlaces” de cada semana.



Profundizando en la misma línea, me he introducido de lleno en Twitter, que puedo decir que ha supuesto todo un descubrimiento. Aunque todavía soy sólo un aspirante a twitteador de los de verdad, estoy cada vez más integrado e identificado con esta nueva vía de comunicación inmediata. A día de hoy, sigo a 38 personas, y 58 followers escuchan mis gorjeos a diario, lo que me permite conversar con gente estupenda y plasmar impresiones y sensaciones en directo, a la vez que retransmitir por esa vía los enlaces que publico en Facebook.



Por otra parte, durante este último año he tenido ocasión de encontrar los primeros patrocinadores para el blog, lo cual, una vez descartado hacerme millonario con los ingresos de Adsense ;-), suponen al menos la posibilidad de sufragar gastos y darme un caprichillo de vez en cuando.



También, gracias a la difusión conseguida, he tenido el privilegio de probar algunos productos (como NDepend, o BaseKit) cedidos directamente por sus creadores, o acceder a información temprana de algunos sistemas (como el Vodafone Business Place) a través de invitaciones a eventos e información suministrada por los fabricantes.



Pero, como ya he dicho en otras ocasiones, el principal beneficio que sigo obteniendo es intangible. La motivación viene con cada post publicado, que brinda una nueva oportunidad de ampliar conocimientos y compartirlos con objeto de aportar un diminuto granito de arena a la comunidad de desarrolladores.



Y es que no hay mejor recompensa que el hecho de que estéis ahí: cada visita, cada suscriptor al feed, cada seguidor, cada comentario o contacto a través de cualquier vía hacen que continuar trabajando en este proyecto valga la pena.



Muchas gracias a todos, y espero que sigáis por aquí, ayudándome a buscar la variable.



Publicado en: Variable not found.



» Leer más, comentarios, etc...

Najaraba.com: Software libre, metodologías ágiles y más.

Apúntate a la CAS2010. Inscripciones

Mayo 10th, 2010 - [Enlace local]

Resucito un rato este blog para anunciar que ya se ha abierto el plazo de inscripción de la conferencia Agile-Spain.Se ha configurado un panel de sesiones y talleres que va a ser muy interesante. Se recibieron muchas sesiones que lamentablemente han tenido que quedar fuera, y han generado un nivel muy alto. Henrik Kniberg también ofrece un taller, pero rápido, que solo para 15 personas.Podeis

» Leer más, comentarios, etc...

Información legal y técnica