miércoles, diciembre 29, 2004

Separación en capas

Existen lenguajes con los que resulta natural la programación en capas y otros con los cuales parecería que no es necesario. En apariencia, si desarrollamos en C#.NET, debemos separar en capas puesto que el lenguaje nos “obliga a programar bien”. En cambio si hacemos una aplicación en ASP, entonces está “bien” poner “todo junto” ya que es un lenguaje de scripting en donde “todo vale”.

Nada de lo anterior es cierto. Es muy fácil programar en C#.NET sin separar en capas, de hecho, he visto muchos desarrollos en los que casi todo el código estaba concentrado en el evento Page_Load. También se puede programar en ASP separando el código en capas.

La separación en capas es, en principio, algo teórico, formal. Se diseña en capas. Podemos desarrollar una aplicación en C# con capa de presentación, de negocios y de acceso a datos en una sola DLL y, aún así, las capas seguirán existiendo. También se puede separar en capas una aplicación íntegramente desarrollada en ASP.

Son muchos los beneficios que obtenemos con esta práctica y, de entre ellos, podemos citar:
  • Clara distribución de las responsabilidades.
  • Nos permite tener múltiples presentaciones para una misma aplicación (ASPX, WebService, Win32)
  • Podemos cambiar de repositorio de datos sin impacto en el resto de la aplicación.
  • Es más fácil trabajar en equipo con otros desarrolladores y hasta armar equipos de desarrolladores para cada capa.
  • El código se vuelve mucho más claro y fácil de mantener.
En los próximos artículos vamos a hablar específicamente de cada capa. También vamos a ir mostrando cómo se puede implementar en ASP tradicional.Esto lo haremos por dos razones fundamentales. En primer lugar, no existen muchos ejemplos de cómo separar en capas con ASP tradicional en Internet. Además intento mostrar lo importante que es diseñar en capas aún cuando la implementación no separe estrictamente el código en DLLs.

martes, diciembre 21, 2004

Diseño independiente de la plataforma

El desarrollo de aplicaciones web tiene varias etapas que, por lo general, son estas:
  • Enumeración de necesidades
  • Creación de especificaciones
  • Análisis
  • Diseño
  • Desarrollo
  • Implementación
  • Mantenimiento
Cada una de estas etapas debe ser independiente de las demás. Esto significa que no debemos permitir que nuestro conocimiento o experiencia acerca de las etapas siguientes interfieran en nuestro criterio sobre la etapa actual.

Particularmente me interesa hacer un comentario sobre la etapa de Diseño debido a que esta y la de Desarrollo suelen ser cumplidas por las mismas personas o, mejor dicho, parte del equipo de desarrollo suele participar en la etapa de Diseño.
Muchas veces he visto, a miembros del equipo, invalidar parte de un diseño porque sería más o menos complicado de desarrollar. Este es uno de los errores más comunes en el desarrollo de aplicaciones en general. Un diseño bien hecho es muy importante como para que sólo quede en una frase de compromiso.

La etapa de Diseño es independiente de la plataforma sobre la que se va a desarrollar. No podemos pensar en que si fuera en ASP entonces estaría bien, pero si fuera en Flash entonces el diseño estaría mal. Si el diseño está bien hecho, seguirá estando bien cualquiera sea la plataforma que se decida utilizar el la etapa de Desarrollo.

martes, diciembre 14, 2004

Simple es mejor

Cuando veo un desarrollo de esos en los que una página ASP usa un objeto SOAP para conectar a un WebService .NET, el cual, vía DCOM se comunica con un servidor que, a través de un motor de persistencia logra actualizar un contador de visitas, lo primero que pienso es: "El programador que hizo esto ha leído mucho".
Lo que verdaderamente despierta mi admiración son aquellas soluciones que resuelven problemas de forma tan sencilla que, luego de implementadas, hacen que todos digan: "era muy fácil".

La regla número uno de los desarrolladores debe ser KISS: "Keep it simple, stupid" (mantenlo simple, estúpido).
Si un problema admite más de una solución, entonces seguramente, la más sencilla será la mejor y la que tendrá menos problemas en el futuro. Por otra parte, cuanto más sencillo se mantenga un desarrollo, más fácil será para un compañero continuarlo.

En una ocación, mi jefe me pidió que resolviera el problema de una página ASP que daba error de "Time Out" debido a que ejecutaba un proceso que habitualmente demoraba mucho tiempo. Luego de analizarlo, llamé a mi jefe y le mostré la solución: la página ya no ejecutaba más ese proceso. No sé si fue mi mejor trabajo, pero seguro que estuvo libre de "bugs".

lunes, noviembre 29, 2004

Administración de errores (parte 2)

Entre las cosas que no debemos hacer cuando administramos errores están:
C# .NET

try {
  Function1();
} catch {}
Function2();

ASP

on error resume next

Function1()
Function2()


En ambos casos se está enmascarando a los errores y no administrándolos. Si bien esto hará que el usuario no vea ningún error, el peligro es muy grande, tal como se describió en el artículo anterior.

Veamos otro ejemplo de lo que no debemos hacer:
C#.NET

public bool DeleteFile(string fileName) {
  bool canDelete=false;
  try {
    System.IO.File.Delete(fileName);
    canDelete=true;
} catch {}
  return canDelete;
}

ASP

Function DeleteFile(fileName)
  On error resume next
  Dim fso, canDelete
  Set fso = CreateObject("Scripting.FileSystemObject")
fso.DeleteFile(fileName)
  Set fso = Nothing
  canDelete = (Err.number=0)
  Err.Clear
  DeleteFile = canDelete
End Function

Esta es una muy mala práctica. Hemos creado una función que intenta borrar un archivo y devuelve el éxito de la operación. Además de las razones dadas en el ejemplo anterior, acá se agrega que quién llama a la función debe revisar si la función tuvo éxito revisando su valor de verdad. Pero en el caso de que la función devuelva falso, no tenemos ninguna otra información útil que nos sirva para tomar decisiones. No es lo mismo que la función haya fallado porque no tiene permisos a que el archivo no exista.

En el próximo artículo veremos algunas buenas prácticas en la administración de errores.

lunes, noviembre 22, 2004

Administración de errores (parte 1)

Nuestro trabajo exige constantemente tomar decisiones. Una de las más importantes es decidir si vamos a administrar errores o no.
Podemos decidir no hacerlo, de hecho podemos definir, en ASP.NET, una página a la que nos debe redirigir la aplicación en caso de error.
Si decidimos administrar errores debemos saber que es toda una responsabilidad. Pocas cosas suponen un riesgo superior a administrar mal los errores de nuestra aplicación.
Empecemos por el principio (que es, generalmente, el mejor lugar para comenzar). Un error es una excepción que no previmos que podía suceder. Lo mejor y menos peligroso que nos puede suceder cuando se produce un error, es que nuestra aplicación interrumpa su ejecución pues, en caso de continuar, estaría ejecutando en “estado de error” y las consecuencias son difíciles de imaginar.
Un amigo me contó la historia del "Medidor de Presión". Imaginemos una caldera que tiene un medidor de presión. Este tiene unos números sobre un fondo blanco y, a partir de cierto valor, otros con fondo rojo que indica peligro. Cuando la presión supera la línea roja suena la alarma. Cuanto más tiempo transcurra la aguja en la zona de peligro más posibilidades hay de que explote la caldera.
Lo mismo sucede con nuestras aplicaciones. Cuanto más rápido salgamos del "estado de error", menos peligro correremos.

martes, noviembre 16, 2004

Paginas de proceso de datos

En nuestra vida como Desarrolladores Web nos encontraremos muchas veces frente a la tarea de hacer formularios en donde los usuarios deberán ingresar información que será almacenada en una base de datos.

Esta tarea, que es tan sencilla como aburrida, hace caer a muchos en uno de los errores más comunes: el terrible F5 destructor. ¿Qué es eso?

Por lo general, para realizar este trabajo, creamos una página con un formulario cuyo destino es la misma página. De esta forma es mucho más sencillo validar del lado del servidor los datos ingresados y, en caso de error, mostrar un mensaje al usuario manteniendo los datos que ha ingresado previamente.

Hasta acá está todo muy bien, pero he visto muchas veces que una vez guardado los datos, se muestra un mensaje de éxito … ¡en la misma página!
Esto significa que si el usuario presiona F5 y recarga la página, el proceso de guardar los datos se ejecutará nuevamente. Este error es muy común cuando usamos objetos como el DataGrid de .NET.

Imaginemos ahora que en lugar de almacenar los datos, debemos enviar un mail. ¿Qué pasará cuando el usuario presione F5?

El peligro que esto encierra es variado y puede ir desde una sobrecarga en el uso de recursos hasta grabar datos repetidos.

Por extensión, se podría decir que: "Toda página de proceso exitoso debe concluir en un Redirect".

martes, noviembre 09, 2004

Qué y cuándo vs cómo

Ya es hora de que empecemos a tratar cosas un poco más concretas y, para empezar, quiero hablar sobre algo que no sólo agrega "estilo" a nuestro trabajo, también lo hace mucho más mantenible.

En una empresa, existen personas que saben lo que hay que hacer y cuándo hay que hacerlo, y otras que saben cómo hacerlo.

En nuestro código debería haber métodos que sepan qué y cuándo hacer las cosas y métodos que sepan cómo hacerlas. No me parece una buena práctica construir métodos que mezclan ambos roles.

Mantener esa separación nos permite ver rápidamente las reglas de negocio por un lado y, de ser necesario, revisar los algoritmos en forma individual. Además, estaremos creando métodos que podrán ser reutilizados en otras lugares de nuestro desarrollo.

Para graficar un poco más este concepto, veamos un ejemplo en ASPX. Necesitamos un método que envía un mail a la dirección especificada en un formulario. Tenemos un HTML en disco con la etiqueta "$$nombre$$" que debemos reemplazar por el nombre del usuario para personalizar el mail. Finalmente, grabamos el mail en nuestra base de datos.

El que sigue es un ejemplo de código muy poco profesional:
private void Button1_Click(object sender, System.EventArgs e)
  // Configuraciones
  NameValueCollection config = ConfigurationSettings.AppSettings;

  // Leer el archivo desde disco
  string mailFile = config["MailFileName"];
  FileStream fs = new FileStream(mailFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
  StreamReader sr = new StreamReader(fs, Encoding.Default);
  string message = sr.ReadToEnd();

  // Reemplazar etiqueta
  message = message.Replace("$$nombre$$", campoNombre.Text);

  // Enviar mail
  MailMessage mail= new MailMessage();
  mail.Subject = config["MailSubject"];
  mail.From = config["MailFrom"];
  mail.Body = message;
  mail.BodyFormat = MailFormat.Html;
  mail.To = campoEmail.Text;
  SmtpMail.SmtpServer = config["SmtpServer"];
  SmtpMail.Send( mail );

  //Grabar a SQL
  string connString = config["ConnectionString"];
  SqlConnection oConn = new SqlConnection(connString);
  SqlCommand dbCommand = new SqlCommand();
  dbCommand.CommandText = "Exec Insert_Email @email=@@email";
  dbCommand.Connection = oConn;
  int rowsAffected = 0;
  oConn.Open();
  try
  {
    rowsAffected = dbCommand.ExecuteNonQuery();
  }
  catch (Exception ex)
  {
    throw new Exception(ex.Message);
  }
  finally
  {
    oConn.Close();
  }
}

Algo con mucho más estilo sería:
private void Button1_Click(object sender, System.EventArgs e)
{
  // Nunca debemos escribir más código del necesario
  // en los métodos que capturan eventos !!!
  EnviarMailAUsuario(campoNombre.Text, campoEmail.Text);
}
private void EnviarMailAUsuario(string nombre, string email)
{
  //Este metodo sabe ques y cuandos

  NameValueCollection config = ConfigurationSettings.AppSettings;

  // 1.- Leer archivo de disco
  string emailSource = LeerArchivoDeDisco(config["MailFileName"]);

  // 2.- Reemplazar etiqueta
  emailSource = message.Replace("$$nombre$$", campoNombre.Text);

  // 3.- Enviar mail
  EnviarMailDelSitio(campoEmail.Text, emailSource);

  // 4.- Guardar el mail
  GuardarMail(campoEmail.Text);
}

Los métodos invocados seguramente tendrán un código parecido a las líneas correspondientes del primer ejemplo. Noten que no estoy especificando en que capa de mi aplicación se encuentran estos métodos, pero deberían estar en una capa diferente de la de presentación.

viernes, noviembre 05, 2004

Todo es importante

- Lo más difícil de un sitio Web es el diseño. Una vez que tenemos un buen diseño, el resto es hacer que las páginas funcionen. (Un diseñador)
- Una vez que tenemos una aplicación que funciona bien, el resto es ponerle colorcitos. (Un desarrollador)
- Lo verdaderamente complicado es satisfacer los requerimientos del cliente con los recursos que contamos y el tiempo del que disponemos. (Un líder de proyecto)
- Lo importante es conseguir los clientes, la gente para hacer las cosas se consiguen así de fácil. (Un ejecutivo de cuentas)

Señores: todo es igual de importante. Sin clientes no hay desarrollo, sin gente que lidere el proyecto nunca terminaremos en tiempo y forma, un sitio Web gusta por cómo se ve, si el desarrollo funciona mal nada sirve finalmente.

Todos los involucrados en un proyecto deberían trabajar a la par y sin menospreciar el trabajo de los demás.

martes, noviembre 02, 2004

Conocer los riesgos

Si queremos ser desarrolladores de sitios web profesionales debemos conocer los riesgos de lo que hacemos. A mí, particularmente, no me alcanza con que algo "haga lo que tiene que hacer", quiero además que lo haga bien.

Una vez que identificamos la mejor opción para un escenario dado, podemos asumir ciertos riesgos. Pero lo que no debemos hacer es elegir una solución sin estar preparados para lo que pueda suceder de acuerdo a los riesgos de dicha solución.

Supongamos que tenemos que hacer una aplicación web muy sencilla como por ejemplo una serie de páginas que piden datos del usuario y al final los graba en una base. Podríamos tomar la decisión de ir guardando los datos en variables de sesión, pero debemos saber que, si por alguna razón las sesiones se pierden (el sitio está hosteado en más de un servidor, los usuario superan el tiempo de expiración de sesión, etc.), nuestra aplicación dejará de funcionar correctamente o aparecerán errores aparentemente aleatorios.

Como regla general debemos conocer cómo funcionan y que hacen todos aquellos componentes que vayamos a usar en nuestros desarrollos. Personalmente no me gusta utilizar componentes de terceros en aplicaciones críticas a menos que tenga disponible el código fuente.

Finalmente les cuento que mi estrategia (no digo que sea la mejor, es sólo la mía) es siempre comenzar pensando que mi desarrollo estará en múltiples servidores y visitado por muchos usuarios concurrentemente. Esa sería mi aplicación ideal. Luego, en función de los requerimientos reales, puedo ir asumiendo determinados riesgos.

viernes, octubre 29, 2004

Cookies

El protocolo HTTP es desatendido. Esto significa que no existe, en principio, relación alguna entre dos peticiones aunque estas sean consecutivas. Para poder mantener una sesión de usuario dentro de una aplicación WEB, tenemos 2 métodos.El usado por la mayoría de los sitios está basado en cookies, el otro en agregar a la URL el ID de se sesión del usuario.

Cada vez que nuestro navegador hace un pedido HTTP, envía todas las cookies válidas para el dominio donde se encuentran los archivos buscados.

He visto sitios que escriben muchas cookies y, además, con nombres y valores muy largos como por ejemplo:
UltimaVisita=23/04/2004 03:25:37 PM

Imaginemos una página que tiene HTML, JS, CSS y 20 GIFs, entonces estaremos enviando la cookie UltimaVisita unas 23 veces.

Debemos usar las cookies en forma racional y responsable. Muchas cookies harán que los usuarios conectados por DialUp naveguen más lentamente. Otra ventaja es que usando menos cantidad de cookies y más pequeñas, estaremos ahorrando ancho de banda de nuestro sitio.
En lugar de
UltimaVisita=23/04/2004 03:25:37 PM
tal vez, podamos usar
UV=20040423

Los grandes sitios de Internet, utilizan servidores dedicados a entregar imágenes. Estos usan un dominio diferente del sitio que navegamos. De esta forma, si el sitio se encuentra en www.sitio.com y las imágenes en www.img.com entonces, nuestro navegador no estará enviando las cookies del sitio cada vez que pide una imagen.

Finalmente quiero comentar algo que no todos tienen en cuenta. Un compañero decía: "Lo que viene del usuario no es confiable". Es muy fácil modificar las cookies que el navegador va a entregar al servidor. Sólo hace falta una sentencia javascript. Por lo tanto, no hay que poner cookies del tipo: admin=si ó idUsuario=27 y si no hay otra alternativa tendremos que encriptarlas.

lunes, octubre 25, 2004

HTML

Siendo desarrolladores web, en la mayoría de los casos, estaremos produciendo páginas HTML. No pretendo hacer aquí un tutorial. Simplemente creo que, para ser mejores desarrolladores, debemos tener un conocimiento profundo sobre HTML. He visto muchos desarrollos que producen páginas inválidas o exageradamente grandes que degradan la calidad de nuestro trabajo

Existen muchísimos recursos disponibles en Internet para aprender. ¡Cuanto más sepamos de HTML, mejor quedarán nuestros sitios!



Desarrollo de aplicaciones web

Hacer que ciertas páginas web tengan funcionalidad, como por ejemplo que envíe un mail, no requiere mucho más que saber escribir el código correspondiente. De hecho, no hace falta ser programador, simplemente se puede buscar en Internet y seguro encontraremos el líneas que necesitamos.

Para hacer una pequeña aplicación web, como mostrar un formulario y guardar la información en una base de datos, requiere además que tengamos algunos conceptos de programación.

Desarrollar aplicaciones web profesionales no es tan sencillo. Debemos saber mucho más que un lenguaje de programación y un poco de HTML. Debemos conocer más profundamente cómo funciona Internet, la plataforma sobre la que vamos a desarrollar, tener en cuenta la envergadura de nuestra aplicación, la cantidad de usuarios que van a ingresar, etc.

En este weblog voy a intentar explicar la forma en la que a mí me gusta desarrollar aplicaciones web y mostrar lo que para mí son errores comunes. Si bien, los ejemplos de código serán en ASP o ASPX, la mayoría de los conceptos creo que son aplicables al desarrollo web en general.