Categoría: ‘Desarrollo’

Como probar diferentes versiones de un mismo código

27-03-2010 | Categoría: Desarrollo

Tengo una necesidad y no se como resolverla, llevo tiempo dándole vueltas, buscando información y no encuentro la forma correcta de hacerlo. Por eso pido que si alguien me pudiera orientar un poco, se lo agradecería.

Necesito poder tener varias versiones de un mismo código PHP corriendo, es decir, tengo la aplicación A en su versión 2 corriendo, pero quiero que algunos usuarios me prueben la versión 3 y otros la versión 4. Claro que eso debe hacerse de forma transparente para el usuario, debe loguearse con la misma dirección, con sus mismos datos, etc.

Una dificultad añadida es la base de datos, pero si resuelvo lo del código esto no me supone mayor problema. Se puede afrontar de varias formas, desde tener las tablas con diferentes nombres según la versión, o diferentes bases de datos para cada versión: bd_v1, bd_v2, etc…. y según se van migrando los usuarios se va pasando de una versión a otra. Claro que según va aumentando el número de usuarios esto se complica, por el tiempo necesario para la migración, pero hay técnicas para ello.

Evidentemente existirá una tabla/lista donde indique cada usuario a que versión de código ha de acceder.

El objetivo, por si alguien necesita una aclaración, es poder hacer pruebas de código sin que afecte al 100% de usuarios. Primero con un grupo reducido de betatesters, luego con uno más amplio y así hasta que se decide pasarlo a todos.

¿Alguien me puede pasar alguna referencia, algún artículo donde se explique cómo resolverlo?, porque se ve que no soy capaz de encontrarlo por mi mismo. Muchas gracias.

Desarrollo multiplataforma

17-09-2009 | Categoría: Desarrollo

Los clientes que tenemos en Arcadina, fotógrafos profesionales en su mayoría, trabajan con dos plataformas Windows y Mac, aunque últimamente, sobre todo desde que Apple se pasó a los procesadores Intel y durante el último año más todavía (no sabemos porqué), Mac parece que esté ganando la “batalla”.

Nuestro software PhotoGestión está desarrollado con Delphi y funciona sobre Windows, yprácticamente a diario se produce una conversación así (más o menos):

- ¿Funciona en Mac? – No, todavía no funciona en Mac – ¿Para cuando estará en Mac? – Pues no sabemos decirle, no tenemos definida una fecha.

Llevo bastante tiempo, a ratos no a full-time, buscando una solución que permita a una empresa pequeña desarrollar para Windows y para Mac, he probado varios entornos, pero ninguno me ha terminado de gustar (debe ser que los comparo con mi estimado Delphi). He estado evaluando Mono+C#, RealBasic, FreePascal+Lazarus, Java, Mono+Delphi Prism y Velneo V7

Mono+C# Es un lenguaje avanzado, con una gran comunidad, con miles de componentes y librerías, es un lenguaje estándar ISO. Mono está apoyado por grandes empresas, es OpenSource y está demostrando

RealBasic casi lo consigue, pero no me decidí por la falta de comunidad, porque no será sencillo encontrar a desarrolladores con experiencia, y porque no encontré algunos componentes que necesitamos si o si.

FreePascal+Lazarus, no llega al nivel, tuve muchos problemas al intentar hacer algo, posiblemente por falta de experiencia, no lo niego. Era el primer candidato, para aprovechar parte del código que tenemos. Espero que alguna empresa (¿Embarcadero?) lo respalde y puedan dedicarle más recursos.

Java, el entorno multiplataforma por excelencia. Muchos puntos a favor: millones de programadores con experiencia, gran comunidad, miles de librerías y componentes, rendimiento más que suficiente para el tipo de aplicación que realizamos, abrumado por la cantidad de documentación y código que hay. Para mí el que más posibilidades tiene.

Delphi Prism he estado leyendo sobre él. Es el Pascal para .NET y Mono. Pero me parece que todavía está verde, hablo con la probabilidad de equivocarme porque no lo he probado.

Velneo V7, con éste entorno me pasa lo mismo que con Delphi Prism, sólo he leído acerca de él. No encontré demasiadas referencias, ni componentes y supongo que no será sencillo encontrar personal con experiencia.

Lo que he sacado en claro durante este tiempo es que:


  1. Es un tema complejo, que igual se escapa a nuestras posibilidades, dados nuestros recursos.

  2. El tema de la apariencia/interfaz: o no se parece a ningún entorno, o si queremos que tenga el look&feel de cada uno se ha de separar por capas y la de presentación hacerla ex-profeso para cada GUI con los widgets que correspondan, con las normas de cada entorno, etc. cosa que complica más el asunto.

  3. Las pruebas y verificaciones se multiplican por mucho.

  4. Temas de instaladores, bases de datos, sistemas de informes, mecanismos de impresión (necesitamos imprimir en una impresora de tickets), etc. Es algo que se multiplica por dos.

  5. Que posiblemente el futuro vaya por SaaS (alquiler de aplicaciones que se encuentran alojadas en servidores ajenos a la empresa que los utiliza), y que por lo tanto este perdiendo el tiempo con ésto. Claro que desarrollar una aplicación vía web tampoco está exenta de retos.


En fin, un mundo apasionante éste del desarrollo de aplicaciones informáticas ;)

mod_rewrite de Apache: una profunda explicación

15-09-2009 | Categoría: Desarrollo

Los que hemos tenido que trastear alguna vez con el mod_rewrite del servidor web Apache sabemos que puede llegar a ser un quebradero de cabeza si se intenta hacer algo complejo. No me considero un experto del tema, apenas he realizado unos pocos, por eso quiero compartir un artículo que he encontrado que creo puede ser de mucha utilidad: http://bit.ly/1f7Oas ¡Que lo disfrutéis!

Tratamiento del AJAX en un solo fichero

18-08-2009 | Categoría: Desarrollo

Últimamente estoy desarrollando sobre todo con PHP+JavaScript (jQuery). En un proyecto interno de Arcadina, que hace un uso intensivo del AJAX, decidí probar un planteamiento diferente del utilizado hasta ahora.

Normalmente las llamadas a la parte AJAX del servidor se hacen a diferentes scripts PHP en función de lo que deseamos obtener (query) o guardar (submit). Por ejemplo, si estamos tratando una lista de clientes podemos llamar a get_cliente.php para solicitar los datos de un cliente pasando su identificador, podemos llamar a delete_cliente.php para eliminarlo o a save_cliente.php para guardar cambios en la ficha, etc. (tengo la manía de utilizar spanglish en el nombre de funciones, procedimientos, etc.). Ejemplo de llamada según esté método:

?Descargar form1.php
1
2
3
4
5
<form name="ejemplo1" action="/api/save_cliente.php" method="post">
<input type="hidden" name="id" value="<?= $cliente->id ?>">
Nombre: <input type="text" name="nombre" value="<?= $cliente->nombre ?>"><br/>
EMail: <input type="text" name="email" value="<?= $cliente->email ?>"><br/>
</form>

Según el proyecto va avanzando nos podemos encontrar con decenas de scripts: get_<em>loquesea</em>, delete_<em>loquesea</em>.... En cada uno de ellos añadir el código de validación, los includes, etc. Se me ocurrió centralizarlo en dos ficheros ajaxsubmit.php y ajaxquery.php, y utilizar un parametro para indicar la acción a realizar. Ejemplo de un formulario utilizando este sistema:

?Descargar form2.php
1
2
3
4
5
6
<form name="ejemplo2" action="/api/ajaxsubmit.php" method="post">
<input type="hidden" name="ajaxsubmit" value="save_cliente">
<input type="hidden" name="id" value="<?= $cliente->id ?>">
Nombre: <input type="text" name="nombre" value="<?= $cliente->nombre ?>"><br/>
EMail: <input type="text" name="email" value="<?= $cliente->email ?>"><br/>
</form>

Como se ve tampoco es que varíe mucho en la parte que se envía al navegador, se añade un nuevo campo oculto “ajaxsubmit” que indica la acción que queremos realizar. Veamos el ajaxsubmit.php:

?Descargar ajaxsubmit.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?php
 
// Incluimos código mínimo de autenticación y librerías
include('includes.inc.php');
 
// Si no está logeado el usuario, devolvemos error
if (!isset($usuario_login) || ($usuario_login == '')) {
 
	$respuesta['resultado'] = 'nok';
	$respuesta['mensaje'] = 'Error: primero debe identificarse';
 
} else {
 
	$respuesta['resultado'] = 'nok';
	$respuesta['mensaje'] = 'Error no identificado';
 
	$ajaxsubmit = $_POST['ajaxsubmit'];
 
	// "AS_" viene de AjaxSubmit ... ;)	
	$funcion = 'AS_' . $ajaxsubmit;
	// Comprobamos que tenemos una función con ese nombre
	if (function_exists($funcion)) {
		$funcion(); // Llamamos a la función AS_ que indique el ajaxsubmit
	} else {
		$respuesta['resultado'] = 'nok';
		if ($ajaxsubmit == '') {
			$respuesta['mensaje'] = 'No se ha indicado "ajaxsubmit"';
		} else {
			$respuesta['mensaje'] = 'AjaxSubmit: orden "' . $ajaxsubmit . '" no reconocida.';
		}		
	}
 
}
 
// Si el resultado es NOK registramos en el log de errores
if ($respuesta['resultado'] == 'nok') {
	error_log('*** AJAXSUBMIT - error - ' . $respuesta['mensaje']);
}
 
// ---------------------------------------------------------------------------------------
// Devolvemos respuesta en formato JSON
$json = new Services_JSON;
echo $json->encode($respuesta);
 
exit;
 
// =======================================================================================
// Procesos de guardar, eliminar, actualizar, etc...
// =======================================================================================
 
function AS_save_cfg() {
 
	global $respuesta;
	$cfg = array();
 
	foreach($_POST as $clave => $valor) {
		// Comprobar si $clave empieza por 'cfg_'
		if (ereg('^cfg_', $clave)) {
			$k = ereg_replace("^cfg_", "", $clave);
			$cfg[$k] = $valor;
		}
	}
	$errormsg = SaveConfig($cfg);
	if ($errormsg == 'ok') {
		$respuesta['resultado'] = 'ok';
		$respuesta['mensaje'] = 'Configuración guardada';
	} else {
		$respuesta['resultado'] = 'nok';
		$respuesta['mensaje'] = $errormsg;
	}
 
}
 
function AS_save_cliente() {
 
	global $respuesta;
 
	// Código simplificado para el ejemplo: se debería
	// añadir validación y protección contra SQL injection
	$cliente = new Cliente($_POST['id']);
	$cliente->nombre = $_POST['nombre'];
	$cliente->email = $_POST['email'];
 
	$errormsg = $cliente->Save();
	if ($errormsg == 'ok') {
		$respuesta['resultado'] = 'ok';
		$respuesta['mensaje'] = 'Cliente guardado';
	} else {
		$respuesta['resultado'] = 'nok';
		$respuesta['mensaje'] = $errormsg;
	}
}
 
?>

La “gracia” del código está en ésta parte:

19
20
21
22
23
24
25
	$ajaxsubmit = $_POST['ajaxsubmit'];
 
	// "AS_" viene de AjaxSubmit ... ;)	
	$funcion = 'AS_' . $ajaxsubmit;
	// Comprobamos que tenemos una función con ese nombre
	if (function_exists($funcion)) {
		$funcion(); // Llamamos a la función AS_ que indique el ajaxsubmit

Lo que se envia en la variable “ajaxsubmit” es el nombre de la función a llamar, pero la precedemos de “AS_” para evitar conflictos con otros nombres de funciones. Entonces gracias a la magia de PHP, porque es un lenguaje de script, aprovechamos la variable $funcion para realizar una llamada a una funcion: $funcion()

¿Qué ventajas tiene este sistema? Tenerlo centralizado, de esa forma, añadir una capa de autenticación o variar el formato de salida de JSON a XML, por ejemplo, es mucho más sencillo. Evidentemente si alguna función es compleja se puede separar en un fichero aparte y hacer el correspondiente include, que además lo recomiendo.

Para facilitar la labor de serializar los inputs de un formulario y enviarlo por ajax estoy utilizando el plugin ajaxForm para jQuery.

Cambio de servidor de www.lagaleriadigital.com

17-05-2009 | Categoría: Desarrollo

Este fin de semana hemos cambiado nuestro servicio LaGaleriaDigital (www.lagaleriadigital.com) de servidor. Era un cambio necesario puesto que en el anterior se venía consumiendo semanalmente un 1% del espacio de disco disponible, y estábamos ya en el 70%. Además de que la conectividad no era adecuada.

El nuevo servidor tiene, de momento, suficiente capacidad tanto de disco como de conectividad, pero aún así estamos ya trabajando para empezar a utilizar el servicio S3 de Amazon, en vistas a ofrecer a nuestros clientes más espacio para almacenar sus fotos.

La migración se ha venido planificando desde hace un par de meses, primero buscando el servidor, luego lo contratamos y configuramos, después empezamos a escribir los scripts que utilizaríamos durante el proceso para tenerlo todo automatizado y más controlado. Además modificamos el software para que la configuración del mismo (rutas, base de datos, librerías, etc.) fuera más sencilla.

Siguiendo los consejos que nos dieron, hemos venido haciendo sincronizaciones (mediante rsync) entre los servidores desde hace unas semanas, aprovechando horas de poco tráfico, para así no tener que volcarlo todo de una vez, solo lo que había cambiado y lo nuevo.

El viernes, a las 22:00 se puso la galería en modo mantenimiento, a las 23:00 se lanzó el proceso de rsync incluyendo la copia de las bases de datos. A las 06:11 del sábado terminó el proceso, que me puse a revisar a las 07:00 y sobre las 10:00, con una pausa para desayunar, había terminado de hacer las pruebas, solicité el cambio de DNS. Para hacer las pruebas cambié el fichero hosts de mi equipo para que apuntara al nuevo servidor.

Hoy domingo, sobre las 10:00 repetí las pruebas una vez las DNS se habían cambiado y todo ha ido perfecto, bueno todo no, un pequeño problema con la configuración del correo que se ha resuelto nada más detectarlo (una redirección de una cuenta a otra).

Nos ha facilitado mucho el que hemos intercambiado las claves SSH de los usuarios de los dos servidores, de forma que hemos podido utilizar scp, rsync, ssh y otros comando desde un servidor hacia el otro.

Para ser la primera vez que hacemos una migración de tantos gigas creo que no nos ha podido salir mejor.