11.07.07

Buenas Prácticas: Agrupando Clases por paquetes/namespaces/grupos de clases

Posted in Buenas Prácticas, Programación at 9:35 pm by Miguel

Siguiendo con las buenas prácticas hoy vamos a hablar de una que tiene que ver con la organización del proyecto, en concreto en la forma en que organizamos las clases, enumeradores e interfaces que lo forman.

Para empezar, os dejo aquí una captura de una aplicación la cual tiene todos sus compenentes sin ningún tipo de organización.

Sin Agrupación

Esta forma de organizarse en principio en un proyecto pequeño puede llegar a ser sostenible, el problema viene cuando la cosa empieza a crecer y a crecer. Cuando esto ocurre la gestión de dichas clases se complica, encontrarlas por ejemplo puede hacerse complicado. Si necesito trabajar con un determinado Enumerador, tal vez me ayudaría el saber que los enumeradores los tengo encapsulados en un grupo (paquete, espacio de nombres…)… o tal vez si tengo definido una clase para acceder a un GPS, me ayudaría a encontrarla el saber que se encuentra contenida en un grupo donde se catalogan todas las clases de acceso a dispositivos externos.

Imagináos por ejemplo, los que conozcáis el framework de Java o el de .NET, si las clases en lugar de estar agrupadas en paquetes o en espacios de nombres, estuvieran todas sueltas. Nos volveríamos locos. Por eso insisto en el hecho de que aplicar esta misma organización en nuestros propios proyectos, ya no sólo mejorá en encontrar más rápido las cosas, si no que además en el hecho de que mantener nuestro proyecto organizado (en todos los sentidos) va a decir mucho de nosotros, sobre todo si el código va a pasar a ser mantenido o auditado por otros grupos de trabajo (incluso por tus propios clientes). No sólo hay que ser un buen profesional, si no que también hay que parecerlo.

Os dejo ahora una captura con las clases anteriores pero organizadas en paquetes.

Agrupando en Paquetes

Y finalmente, la agrupación, pero desplegada para que veáis qué se ha metido en cada paquete.

Agrupado en paquetes y desplegado

Otro tema a parte es cómo jerarquizar los paquetes, eso ya os lo dejo a vosotros porque va a depender de vuestra forma de trabajar o tal vez del proyecto e incluso de vuestra empresa. Con suerte tendréis estipulado cual es la jerarquía básica para vuestros proyectos y partiréis de ella.

Un saludo.

Miguel.

Rating 3.00 out of 5
[?]

10.17.07

Buenas Prácticas: Legibilidad y Mantenibilidad del Código

Posted in .NET, Buenas Prácticas, Gestión del Mantenimiento, Programación at 3:46 pm by Miguel

Y es que muchas veces nos olvidamos de que nuestro código va a tener que ser interpretado, leído y mantenido por otras personas, o incluso por nosotros mismos en un futuro.

Mantener estructuras similares a la hora de programar, un estilo de programación, un orden determinado y un código claro, harán que la mantenibilidad de nuestras aplicaciones se dispare. Este aspecto se ve aún más potenciado en grupos de trabajo de alta volatilidad, donde la estabilidad del número de profesionales que forman el grupo es alta. Me refiero tanto a la baja de miembros del equipo como a la rápida incorporación de nuevos profesionales para aumentar el tamaño del grupo.

Quisiera dejar patente la diferencia de legibilidad y mantenibilidad entre dos fragmentos de código que llevan a cabo exactamente la misma funcionalidad

Ejemplo de baja legibilidad y mantenibilidad (código C#):

public bool NumPuerMayorQue(int t)
{
    int n = 0;
    coche[] lista = DameListaCoches();
    for(int i=0;i<lista.lenght;i++)
        n = n + (coche)lista[i].NumPuertas;
    if (n>t)
        return true;
    else
        return false;
}

Ejemplo de mejor legibilidad y mantenibilidad

/// <summary>
/// Añade un nuevo parámetro a la lista
/// </summary>
/// <param name=”numPuertas”>Número de puertas a comparar</param>
/// <param name=”lista”>Lista genérica de coches sobre la que hacer el cálculo</param>
/// <returns>Retorna verdadero en el caso de que la variable numPuertas pasada por parámetro sea mayor que el resultado de sumar todas las puertas de los coches pasados por parámetro en la variable lista. Retorna falso en caso contrario, es decir cuando es menor o igual.</returns>
public bool IsNumeroPuertasMayorQue(int numPuertas, List<coche> lista)
{
    int total = 0;

    foreach (coche unCoche in lista)
    {
        total += unCoche.NumPuertas;
    }

    return (total > numPuertas);
}

Aspectos que hacen notar la mejora de la mantenibilidad y la legibilidad de ambas funciones

1) Se dispone de un comentario sobre qué labor va a realizar la función, qué papel juega cada uno de sus parámetros y qué valores se esperan retornar y en qué condiciones.

2) El nombre de la función, al marcar el prefijo “Is” ya nos da la pista de que va a devolvernos un booleano. IsNumeroPuertasMayorQue da más pistas al desarrollador que NumPuerMayorQue.

3) La lista de coches es pasada por parámetro a la función, siendo además una lista genérica. Sabemos exactamente de dónde nos llega la lista.

4) Uso de foreach en lugar de for. Usando foreach aumentamos la legibilidad y la elegancia de nuestro código.

5) Uso de lista genérica en lugar de arrays. Nos estamos evitando hacer el cast “(coche)lista[i]“, que además no nos asegura que lo que realmente tenga la lista sean objetos de tipo coche, puede darse un error de casting.

6) El nombre de las variables utilizadas es mucho más descriptivo.

7) Llaves en sentencias de una sóla línea. Realmente funcionan igual, pero si a las sentencias for, foreach, if y else le añadimos llaves de apertura y cierre aunque incluyan una única sentencia, lo leeremos mejor.

8) Creo que queda bastante claro que se lee mejor “return (total > numPuertas)”

9) Una linea en blanco entre bloques. ¿La vista lo agradece, no?

Saludos.

Miguel.

Rating 3.00 out of 5
[?]

10.03.07

ClasesAvanzadas v1.0.0.0

Posted in .NET, Buenas Prácticas, ClasesAvanzadas.dll, Programación at 8:41 pm by Miguel

Fruto del anterior post sobre buenas prácticas, se me ha ocurrido la idea de ir añadiendo las clases que os vaya comentando en una dll, para que así podáis probar su funcionamiento y aprovecharlas para vuestros desarrollos. La dll está realizada en C# y podréis referenciarlas en vuestros proyectos con la plataforma .NET

En la primera release incluyo la clase Redireccion, que os ayudará a hacer más legibles y mantenibles vuestros response.redirect.

ClasesAvanzadas.dll v1.0.0.0

Se aceptan comentarios, mejoras, errores…

Saludos.

Miguel

Rating 3.00 out of 5
[?]

Buenas Prácticas: Encapsular Construcciones Complejas

Posted in .NET, Buenas Prácticas, Programación, Web at 1:51 pm by Miguel

Supongo que estaréis acostumbrados a ver cosas como estas (código C#)

Response.Redirect(“~/home/pepito.aspx?idarticulo=” + idarticulo.toString() + “&idusuario=” + idusuario.toString() + “&idcategoria=” + idcategoria.toString() + “&activo=” + activo);

En el caso del ejemplo tenemos la instrucción response.redirect, la cual muchos de vosotros conoceréis, y que se encarga de redireccionar a nuestro navegador a la url que se le pasa por parámetro. Muchas veces vamos a necesitar pasar valores en la URL para que sean recogidas en la página de destino, y “no nos queda más remedio” que hacerlo de esta manera.

La verdad es que para redirecciones con urls sencillas aún es tratable, pero como tengamos que empezar a concatenar parámetros y más parámetros, te puedes volver loco. Por ello, una buena práctica resulta el encapsular todos estos oomportamientos para ayudar en la lectura del código y el posterior mantenimiento de la aplicación.

Os dejo aquí el comportamiento de hipotética clase que encapsula esta buena práctica, a ver si qué os parece (código C#)

Redireccion miURL = new Redireccion(“~/home/pepito.aspx”);
miURL.AddParameter(“idarticulo”, idarticulo);
miURL.AddParameter(“idusuario”, idusuario);
miURL.AddParameter(“idcategoria”, idcategoria);
miURL.AddParameter(“activo”, activo);
miURL.Ir();

¿Cómo lo leéis mejor? ¿Os hacéis una idea de lo que hace por dentro la clase, no?

AddParameter es un método sobrecargado donde el primer parámetro es el nombre y el segundo el valor. Podemos pasarle como valor diferentes tipos de datos, ya que está sobrecargado con el tratamiento para cada uno de ellos.

El constructor acepta un parámetro de entrada que es la base de la url a la que vamos a llamar, aunque podríamos instanciar la clase sin pasarle ningún parámetro, y luego usar la propiedad miURL.URLBase para definirla.

Por supuesto, y siguiendo las buenas prácticas, la clase Redirección debería encapsular también sus excepciones propias que lanzaría en los casos necesarios y que podrían capturarse desde fuera. Por ejemplo, ¿y si instanciamos la clase sin pasarle la URL base y tampoco la añadimos usando la propiedad? Al lanzar el método Ir() debería saltar una “NoHayURLBaseDefinidaException”, ¿no creéis?

Otro consejo para rematar, sería sobreescribir el método toString() de la clase, para que devolviera la URL generada hasta el momento, y así poder hacer cosas del tipo:

MostrarMensaje(“Esta es la URL Generada: “+  miURL);

Esta forma de encapsular las construcciones complejas es aplicable a otros campos, como por ejemplo para generar una secuencia SQL. Otro día os dejo un ejemplo.

Saludos.

Miguel.

Rating 3.00 out of 5
[?]

09.26.07

Buenas Prácticas: Definición de Excepciones Propias

Posted in Buenas Prácticas, Programación at 8:44 pm by Miguel

Inicio una nueva saga de opinión relacionado con las buenas prácticas. La primera, está relacionada con la programación, en concreto con la creación de excepciones propias, relacionadas con las clases que vayamos generando.

Para los que no conozcan o no hayan trabajado con excepciones, me ahorro la definición y me uno a la reutilización de código: http://es.wikipedia.org/wiki/Manejo_de_excepciones

Una vez situados en el contexto, paso a describir la práctica con un ejemplo.

Supongamos que utilizamos una clase que nos ayudará a extraer datos de un dispositivo GPS, que en un alarde originalidad vamos a llamar “GPS”. La clase tiene varios métodos y no tenemos acceso al código, ya que la importamos a traves de una dll.

1) CountSatelitesDisponibles(): Retorna el total de satélites disponibles para el dispositivo GPS
2) GetLongitud(): Retorna la longitud actual
3) GetLatitud(): Retorna la latitud actual
4) Conectar(): Conecta el dispositivo GPS
5) Desconectar(): Desconecta el dispositivo GPS
6) IsConexion(): Retorna verdadero si hay conexión con el gps, retorna falso en caso contrario

Si nos pusiéramos en marcha para utilizar la clase en nuestra aplicación, podríamos crear algo similar a esto (uso sintaxis C#)

public void miMetodo()
{
    try
    {
        GPS objeto = new GPS();
        objeto.Conectar();
        if (objeto.IsConexion())
        {
            if (objeto.countSatelitesDisponibles()>=4)
            {
                // mostrarPorPantalla es un
                // método que genera una pantalla
                // emergente
                mostrarPorPantalla(objeto.GetLongitud());
            }
        }
    }
    catch(Exception ex)
    {
        // tratarExcepcion es un método
       // que se encarga de mostrar el
       // mensaje por pantalla.
        tratarExcepcion(ex);
    }
    finally
    {
        objeto.Desconectar();
    }
}

¿Qué ocurriría si se produce alguna excepción en la ejecución del código? Pues se haría el catch con el objeto Exception, y tratarExcepcion se encargaría de mostrar un mensaje por pantalla. Si hemos tenido suerte que en la definición de la clase GPS el desarrollador incluyó una excepción genérica con un mensaje de texto, con suerte almenos en ex.Message tendremos parte de la descripción del error. Es todo lo que podríamos hacer desde la llamada a la clase GPS con las herramientas que nos brinda. No somos capaces de tratar la excepción en la conexión, o en el recuento de satélites desde nuestro código, ya que no sabemos cúando se produjo el error allí (si hay mensaje podríamos mirar el mensaje… pero eso es una cutrez nada recomendada y menos en este artículo)

A continuación dejo aquí lo que sería la definición del método Conectar de la clase GPS lanzando excepciones genéricas

public void Conectar()
{
    try
    {
        // Código encargado de conectar el dispositivo GPS
    }
    catch(Exception ex)
    {
        throw new Exception(“Error al conectar”);
    }
}

¿Y si en lugar de utilizar excepciones genéricas dejáramos definidas excepciones propias de la clase y las lanzáramos a estas en lugar de usar la excepción genérica?

public void Conectar()
{
    try
    {
        // Código encargado de conectar el dispositivo GPS
    }
    catch(Exception ex)
    {
        throw new NoSeHaPodidoConectarConElGPSException();
    }
}

public class NoSeHaPodidoConectarConElGPSException:Exception
{
    public NoSeHaPodidoConectarConElGPSException() : base(“Error Conectando”) { }
}

Esto ya es otra cosa, ya que ahora, desde nuestra aplicación podremos tratar exáctamente cual ha sido la excepción que se ha producido. Fijaros:

public void miMetodo()
{
    try
    {
        GPS objeto = new GPS();
        objeto.Conectar();
        if (objeto.IsConexion())
        {
            if (objeto.countSatelitesDisponibles()>=4)
            {
                // mostrarPorPantalla
                // es un método que genera
                // una pantalla emergente
                mostrarPorPantalla(objeto.GetLongitud());
            }
        }
    }
    catch(GPS.NoSeHaPodidoConectarConElGPSException ex)
    {
        //mandarEmailServicioTecnicoGPS se 
        //encarga de coger la excepción,
        // generar un email con la información
        // que incluye y mandarlo al técnico
       // con menor carga de trabajo de nuestra
       // organización.
        mandarEmailServicioTecnicoGPS(ex);
    }
    catch(Exception ex)
    {
        // tratarExcepcion es un método que
        // se encarga de mostrar el mensaje
        // por pantalla.
        tratarExcepcion(ex);
    }
    finally
    {
        objeto.Desconectar();
    }
}

¿Mucho mejor no? ¿Merece o no merece la pena el definir excepciones propias?

Saludos.

Miguel.

Rating 3.00 out of 5
[?]

« Previous Page « Previous Page Next entries »