10.08.08

Autenticación con AgilePoint y el uso de Surrogate

Posted in .NET, AgilePoint, BPM, Programación, Servicios Web, Web at 9:34 pm by Miguel

Una de las principales capacidades que ofrece AgilePoint como producto, es la orientación a servicios que han dado a la solución de software. Para ello, en la versión 4.0 de la herramienta ofrecen en concreto dos servicios que agrupan todos los métodos que permiten acceder a la funcionalidad del motor.

workflow.asmx

Servicio que encapsula todos los métodos asociados a la manipulación de los flujos (incluyendo por ejemplo servicios para instanciar plantillas, obtener información de un proceso, establecer el valor de una de las propiedades de un proceso…).

admin.asmx

Servicio que encapsula todos los métodos asociados a la administración del propio motor (incluyendo por ejemplo servicios específicos para la creación de usuarios, permisos, roles…).

A priori, con estas dos piezas, y desde cualquier tipo de tecnología cliente, podríamos manipular el BPM desde una aplicación cliente creada por nosotros mismos.

La pieza que aquí nos falta es conocer cómo se protege AgilePoint para que no todos los usuarios que tengan acceso a dichos asmx puedan utilizarlos para acceder al motor y manipularlo a su gusto. Como comprenderéis, si no existiera dicha autenticación estaríamos hablado de un fallo de seguridad como la copa de un pino.

El requerimiento indispensable para poder acceder a los servicios, es que el mismo objeto que está realizando la conexión al servicio cuente con las credenciales de red del usuario que está haciendo la llamada. Esto ya en principio garantiza que la persona que está llamando al servicio está autenticada en el dominio, que quieras que no, supone una primera barrera de seguridad. Pero esto, no es suficiente, ya que necesitaremos que el usuario que esté haciendo la llamada también esté dado de alta en la propia base de datos de usuarios de Agilepoint. Como curiosidad, remarcar que la propia herramienta de gestión de usuarios de AgilePoint provee de facilidades para sincronizarse con el directorio activo e importar la información de los usuarios de dicho directorio a la base de datos de usuario de AgilePoint.

Resumiendo, si disponemos de nuestras credenciales de red validadas, se las pasamos a AgilePoint y nuestro usuario está también incluido en el repositorio de usuarios de AgilePoint, olé, ya podemos usar los servicios sin problemas.

Pongamos por ejemplo que estamos trabajando con una aplicación de escritorio que referencia los servicios web de AgilePoint directamente. Siguiendo este procedimiento, conseguiremos autenticarnos sin problema.

La casuística complicada viene cuando por ejemplo trabajando en web, o en el caso de que no conectemos directamente con nuestra aplicación al servicio, si no que tengamos otra aplicación que haga la conexión en nuestro nombre. Estaríamos hablando de una típica aplicación web, donde el usuario que la está ejecutando es del del pool del servidor de aplicaciones y no la persona que ha abierto el navegador en su casa… o en el caso de que nuestra aplicación de servicios no ataque directamente a los servicios de AgilePoint si no que llame a una capa de negocio con orientación a servicios que sea la que se encargue después de llamar a Agilepoint. En ambos casos tenemos “algo”por enmedio que tiene sus propias credenciales que no son precisamente las nuestras.

Ante este problema tenemos una primera solución para lograr la autenticación, nos creamos un usuario para ese “algo” intermedio en nuestro directorio activo, lo damos de alta también en la base de datos de Agilepoint, y ala, cuando llamemos al “algo” este se podrá autenticar y hacer el trabajo sin problemas. Esto funciona, pero tiene un problema de base, que todos los usuarios trabajarán contra el BPM usando el mismo usuario, y esto va en contra del funcionamiento basado en flujos.

Como hemos tratado ya en otros artículos, uno de los componentes principales de un motor de flujo es el responsable de cada una de las tareas definidas en el flujo de trabajo. Parte de la gracia de este sistema de trabajo es que la persona que conoce el negocio define las responsabilidades de cada uno de los pasos a seguir, y a partir de esta responsabilidad, los usuarios asignados tendrán constancia de que tienen que realizar cada una de las tareas. Imaginaos entonces que siguiendo un flujo determinado se asigna la responsabilidad de las tareas generadas a una serie de usuarios. ¿Cómo voy a conseguir entonces preguntarle al motor de flujo que me de las tareas de dicho usuario específico si siempre estoy haciendo login a través de un usuario intermedio común a todos? En este caso todos seríamos el mismo usuario y recibiríamos siempre las mismas tareas.

Después de toda la puesta en situación inicial llegamos entonces al punto clave y objetivo del artículo, el Surrogate. Mediante la “surrogación” (no creo que esté este palabro en ningún diccionario) conseguimos decir en la autenticación que el usuario intermedio común a todos hable en nombre de otro. Es decir, nos autenticamos igual, pero en un momento dado dicho usuario le dice a AgilePoint: “Oye tío, yo soy el que me autentico siempre, estas son mis credenciales y seguro que además me tienes en tu base de datos, y, a partir de ahora mismo todas las operaciones que voy a mandarte las voy a hacer en nombre de Pepe, por lo tanto, cuando te pida que me des todas las tareas en estado ofrecido me estoy refiriendo a las de Pepe, y cuando te diga que proceses una tarea lo vas a hacer también en nombre de Pepe”.

Claro está, “Pepe” va a tener que estar dado de alta en el repositorio de usuario de AgilePoint, o si no por mucho que le diga “el de siempre” que va a hablar en nombre de “Pepe”, AgilePoint va a responder: “no sé de quién me estás hablando”.

A partir de aquí, para ver a nivel de código cómo funciona esto, os dejo un link de la página de Ascentn donde podéis ver el ejemplo:

Ejemplo KB-Ascentn

Para acabar, y como podréis ver en el link que os acabo de dejar, no todos los usuario disponibles en el repositorio de usuarios de AgilePoint tienen la capacidad de hablar en el nombre de otros. Para disponer de dicha capacidad, se debe dar de alta el usuario como “Impersonator” a través de la herramienta de configuración del servidor de AgilePoint.

Espero haberme explicado con suficiente claridad, no es precisamente fácil intentar trasladar el uso del Surrogate.

Saludos.

Miguel.

Rating 3.00 out of 5
[?]

09.25.08

Ajax Control Toolkit

Posted in .NET, Programación, Web at 7:46 am by Miguel

Aprovecho los tres minutos diarios que tengo últimamente para el blog para añadir una referencia

http://www.asp.net/ajax/

Dos meses ya trabajando con el Toolkit + .NET Framework 3.5 con resultados satisfactorios.

Saludos.

Miguel.

Rating 3.00 out of 5
[?]

09.04.08

TableAdapters Transaccionales sin usar TransactionScope

Posted in .NET, Bases de Datos, Programación at 3:17 pm by Miguel

La verdad es que el mundo de los TableAdapters y los Datasets Tipados abre muchísimas puertas de cara a la productividad en el desarrollo y a la disminución de tasa de errores a la hora de trabajar contra una fuente de datos.

El problema que nos hemos encontrado muy amenudo es querer utilizarlos transaccionalmente pero sin emplear la herramienta TransactionScope de ADO.NET, y seguir utilizando una conexión y transacción controlada por nosotros mismos. No sé por qué pero en su día intenté hacerlo así y no hubo manera y tuve que morir al palo del TransactionScope. Recientemente ha vuelto a surgir la necesidad, y, esta vez con Visual Studio 2008 y el Framework 3.5, parece que la cosa ha funcionado.

No sé si es cosa del Framework 3.5 (en su día lo intenté con la versión 2.0), o que hoy me ha dado por estar lúcido, o las otras veces demasiado poco lúcido, pero hoy con una tontería de código he conseguido trabajar de forma transaccional entre dos TableAdapters que están en dos Datasets distintos, compartiendo la misma conexión y transacción.

Sin más rodeos, el código:

public void InsertMarca(string marca, int veces)
{

SqlTransaction tran = null;
SqlConnection con = null;

try
{
// abrimos una conexión
con = new SqlConnection(“Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\BBDD.mdf;Integrated Security=True;User Instance=True”);
con.Open();

//establecemos que la conexión de la marca es la que hemos creado
MarcaTableAdapter adapterMarca = new MarcaTableAdapter();
adapterMarca.Connection = con;

// establecemos que la conexión del coche es la que hemos creado
CocheTableAdapter adapterCoche = new CocheTableAdapter();
adapterCoche.Connection = con;

// iniciamos una transacción sobre dicha conexión
tran = con.BeginTransaction();

// le pasamos a los adaptadores la transacción que acabamos de crear
adapterMarca.Transaction = tran;
adapterCoche.Transaction = tran;

for (int i = 0; i < veces; i++)
{
adapterMarca.InsertMarca(marca);
adapterCoche.InsertCoche(“4444-cxv”, 4, 8);
if (i > 10)
{
// forzamos un error para ver qué pasa
throw new Exception(“prueba de transacción”);
}
}
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
}
finally
{
con.Close();
}

}

Aquí la pieza que falta es la siguiente, en el diseñador de Datasets, hay que irse a las propiedades de cada uno de los TableAdapter implicados, y establecer la propiedad “ConnectionModifier” a “public”.

Existen otras soluciones a este mismo problema que podéis encontrar descritas en el siguiente artículo que explica bastante bien el problema:

http://www.codeproject.com/KB/dotnet/transactionta.aspx

En concreto el autor del artículo defiende una solución utilizando Reflection, ya que el otro tipo de solución con la que se suele trabajar para este mismo problema es con el uso de clases parciales.

El problema del uso de las clases parciales es que necesitas generar una clase parcial por cada uno de los TableAdapters, y esto a la larga puede hacer generar mucho código. La solución con Reflection tampoco es la panacea, ya que aunque te evites generar una clase parcial por TableAdapter, aparece el problema de siempre al utilizar Reflection, que nadie te garantiza que tras una actualización del framework la propiedad que has explotado cambie su nombre…

La solución que aporto tiene alguna ventaja, por ejemplo no usa Reflection así que nos evitamos problemas de compatibilidades futuras, tampoco es necesario generar una clase parcial por TableAdapter, lo único que tendremos que hacer es en los casos de actuar de forma transaccional (por experiencia el volumen de accesos transaccionales a base de datos no suele llegar ni a la mitad de los accesos de modificación en base de datos) añadir algunas líneas más en el código.

Eso sí, hay una cosa que no me gusta un pelo, que es que tengamos ahí en el código la apertura y el cierre de la conexión. Que nos dejemos la apertura lo veo complicado ya que si lo probamos aunque sea una vez nos dará error. El terrible problema lo veo en el cierre de la conexión, ya que es la historia de antaño, como te dejes el finally acabas de reventar tu sistema. Dándole más vueltas, este problemas con una clase que maneje la conexión, que herede de la interfaz IDisposable y que utilicemos mediante un using podríamos solventar el problema de olvidarnos cerrar la conexión, pero vamos a seguir teniendo que tragarnos el asignar la conexión y la transacción a todos los adapters que participen.

Saludos.

Miguel.

Rating 3.00 out of 5
[?]

05.22.08

¿Servicios Web Polimórficos? (Parte 2 – Solución con WCF y Framework 3.5)

Posted in .NET, Programación, Servicios Web, WCF, Web at 8:47 pm by Miguel

Hace ya bastantes artículos atrás estuvimos hablando de Servicios Web y Polimorfismo (aquí). Introdujimos el tema y le dimos alguna vuelta a la necesidad de poder aplicar el concepto de polimorfismo a las llamadas de un servicio web. Es más, incluso lo intentamos utilizando Servicios Web en .NET mediante el Framework 2.0… y… comprobamos que no era posible.

Quedaron abiertas otras soluciones, pero hasta el momento no había podido invertir tiempo en este tema, así que ahora que ya tengo algo que mostraros, allá vamos!

Para empezar, como habréis podido observar la solución parte del uso de WCF (Windows Communication Foundation). En concreto para la solución he empleado Visual Studio 2008 y el Framework 3.5 (remarco lo de la versión del Framework, ya que esta misma solución utilizando el WCF y el Framework 3.0 no os va a funcionar, ya que no se hace igual). Estamos de suerte y la solución con el Framework 3.5 la verdad es que es sencillísima.

Paso a mostraros fragmentos de código sueltos y luego os adjuntaré el proyecto para que podáis ver y probar vosotros mismos que funciona. Eso sí, avanzo que el código del proyecto es simplemente para probar el funcionamiento así que le faltarán comentarios y demás cosas que intentaré añadir directamente aquí.

Bien, antes de nada empezar diciendo que voy a intentar seguir la guía del primer intento que hicimos de Servicios Web Polimórficos, en la que la idea era conseguir tener un único Servicio Web que nos ofreciera la posibilidad de realizar el mantenimiento de infinitas entidades de datos, en lugar de tener un servicio diferente para cada una de ellas. Para hacerlo necesitábamos que el cliente que consume el servicio recibiera en la definición de su WSDL las clases que implementaban la interfaz IDTO, pero no había manera de que la aplicación de servicios al generar el WSDL lo hiciera de forma automática.

La idea sería tener un servicio web que tuviera métodos como los siguientes (para los que no conozcan la teoría de los DAO, DTO y Factorías, podéis encontrar literatura en la categoría de patrones de este mismo blog):

public void Insert(IDTO dto)
{
    Factory.GetDAO(dto).Insert(dto);
}

public void Update(IDTO dto)
{
    Factory.GetDAO(dto).Update(dto);
}

public void Delete(IDTO dto)
{
   Factory.GetDAO(dto).Delete(dto);

Como véis esto sería la leche ya que cualquier llamada al servicio sería capaz de ejecutar la acción independientemente del DTO que le llegue…

Por aquí dejo el código de la factoría, que como véis, según el DTO que recibe, retorna el DAO correspondiente.

public class Factory
{
   public static IDAO GetDAO(IDTO dto)
   {
       if (dto is CocheDTO)
       {
          return CocheDAO.GetInstance();
       }
       else if (dto is MarcaDTO)
       {
          return MarcaDAO.GetInstance();
       }
       throw new Exception(“no existe este dto”);
    }
}

Además, como podréis observar, todos los DAO heredan de IDAO, que es quien define los métodos con los que un DAO puede trabajar, y es lo que usa la factoría para actuar con independencia.

Pero bueno, vamos al grano y a lo que interesa, que es cómo conseguir que se entere el cliente que recibe el servicio de los DTO que pueden heredar de IDTO. La clave está cuando definimos la clase IDTO.

[DataContract]
[KnownType(typeof(DTO.CocheDTO))]
[KnownType(typeof(DTO.MarcaDTO))]
public class IDTO
{
}

Sobre la clave DataContract, ya hablaremos cuando hagamos la introducción a WCF, en lo que quiero que os fijéis es en las claves KnowType. Aquí es donde estamos marcando al servicio que IDTO tiene como tipos conocidos otras clases, que son las que heredan de ella. Por cierto, habréis visto que IDTO es una clase y no un interfaz… por lo visto el atributo KnowType no puede utilizarse con interfaces, pero bueno nos da lo mismo en este caso.

Con todas estas combinaciones que os he presentando, y si probáis el ejemplo donde tenéis más código, veréis que en el cliente que se ha montado (que es una aplicación de escritorio con un botón), podréis leer el siguiente código:

Servicio.MiServicioClient cliente = new Servicio.MiServicioClient();
Servicio.CocheDTO coche = new Servicio.CocheDTO();    
Servicio.MarcaDTO marca = new Servicio.MarcaDTO();     

coche.Codigo =1;
coche.Matricula=”IB-4444-TRT”;
coche.NumeroPuertas=1;
cliente.Insert(coche);

marca.Codigo = 4;
marca.Nombre = “Mercedes”;
marca.Pais = “España”;
cliente.Update(marca);

Bingo! El cliente es capaz de instanciar objetos que no son retornados o pasados por parámetro explícitamente por un método de un servicio (que era uno de los problemas que teníamos con el Framework 2.0). “Mágicamente” podemos utilizar los DTO en cliente, rellenarlos y pasárlos a los correspondientes métodos de Insert y Update. Al llegar la petición al servicio, la factoría decide el DAO a llamar en tiempo de ejecución y a correr.

Con un único servicio podríamos realizar toda la fachada para mantener y consultar infinitas entidades de negocio. ¡Objetivo cumplido!

Os invito a descargar la solución de ejemplo que os adjunto y a lanzarla en modo debug, veréis que si lo seguís la ejecución mantiene el flujo que hemos definido sin problemas.

Servicio WCF Polimórfico

Saludos.

Miguel.

Rating 3.67 out of 5
[?]

05.08.08

Caché en la Capa de Acceso a Datos

Posted in Arquitectura, Bases de Datos, Programación at 11:28 pm by Miguel

En muchas aplicaciones suele ser común que existan conjuntos de datos que cambien muy poco o nada a lo largo del tiempo. Por ejemplo, si almacenamos en nuestra base de datos tablas con Países, Provincias, Comunidades Autónomas… lo más seguro es que los registros que conformen la tabla no varíen en el tiempo o si lo hacen sean cambios totalmente excepcionales.

Si esto es así e imaginando el típico formulario web donde tenemos que seleccionar un desplegable con provincias, podría resultar ineficiente hacer una consulta a base de datos por cada carga del formulario que realizaran los distintos usuarios de la aplicación. ¿Para qué vamos a consultar otra vez la base de datos si podemos asegurar en un 99% que no habrán cambiado? Sobre todo teniendo en cuenta que el acceso a base de datos suele ser de lo que más penaliza el rendimiento de una aplicación.

Una buena idea sería que en según que métodos de nuestra capa de acceso a datos, antes de realizar una consulta directa a una tabla, comprobáramos si los datos ya se han almacenado en entidad física mucho más rápida de acceder que la base de datos, por ejemplo, en una caché. Inicialmente esta caché estaría vacía, en la primera carga se rellenaría a partir de la información de la base de datos, y el resto de veces ya se atacaría siempre a la memoria cache.

El resultado, claramente es un tiempo de respuesta mucho más bajo en cada transacción de este tipo.

¿Algún ejemplo con pseudo-codigo?

public Lista<ProvinciaDTO> GetProvincias()
{
  if (IsVacio(CacheProvincias))
  {
    CacheProvincias = RellenaConAccesoATablaProvincias();
  }
  return TransformaCacheEnLista(CacheProvincias);    
}

Como véis sólo rellenaremos la caché de provincias con los datos de la tabla si la caché está vacía, si no lo está, directamente retornaremos los datos desde la caché.

En el pseudo-código no se están resolviendo temas de concurrencia (cómo resolver si dos usuarios al mismo tiempo comprueban si está vacío y da verdadero), y se abstrae 100% la solución propia de cómo cachear precisamente para hacerlo independiente de la tecnología en que queráis aplicar el método.

Otro tema interesante que podrían incorporarse, es la posibilidad de que la caché caduque, es decir, que no se almacene la información en la caché de forma infinita mientras la aplicación no se reinicie, si no que se establezcan periodos temporales en los como máximo la caché será renovada. Por ejemplo si tenemos una tabla que almacene Marcas puede que nos interese que se reuneve la caché cada 24 horas ya que almenos una vez al día se añade una marca nueva (me lo estoy inventando obviamente, es por dar un ejemplo). Si ante la petición de un usuario se comprueba que la caché está caducada, esta se vaciaría y se volvería a rellenar de forma automática tras una consulta a la tabla correspondiente de la base de datos.

¿Interesante?

Saludos.

Miguel.

 

Rating 3.00 out of 5
[?]

04.30.08

Patrón de Diseño: Memento

Posted in Java, Patrones, Programación at 9:40 am by Miguel

Me hace mucha gracia el nombre de este Patrón de Diseño, “Memento”, inavitablemente me recuerda siempre a la película.

Memento nos ayuda por ejemplo a resolver la típica problemática de máquina de estados, donde necesitamos almacenar cuáles han sido los diferentes estados que ha tenido un objeto a lo largo de un tiempo determinado.

Un ejemplo muy cercano a todos nosotros es el uso del “Undo / Deshacer” (CTRL+Z) del que disponen la mayoría de procesadores de texto, entornos de desarrollo… y que nos permite en un momento dado poder deshacer todos los últimos pasos que hemos llevado a cabo. Para hacer esto alguien se habrá tenido que acordar de lo que habíamos hecho antes, y ese alguien es el Patrón Memento.

Os dejo link a la wikipedia

http://es.wikipedia.org/wiki/Memento_(patr%C3%B3n_de_dise%C3%B1o)

Y un link a un PDF donde tenéis una descripción más ampliada, además de un ejemplo de codificación en Java.

http://www.freewebz.com/amanecer/personal/papers/paper.memento.pdf

Un saludo.

Miguel.

Rating 2.00 out of 5
[?]

04.24.08

AIR

Posted in AIR, Framework, Programación, Web at 2:16 pm by Miguel

¿Habíais soñado alguna vez con la posibilidad de convertir vuestras aplicaciones web directamente como ejecutables en vuestro escritorio? Pues parece que alguien ha escuchado vuestras plegarias.

AIR (Adobe Integrated Runtime) es la nueva baza de Adobe para poder desarrollar fácilmente aplicaciones de escritorio a partir de aplicaciones web. ¿Parece el mundo alrevés verdad? Esta nueva forma de producir software intenta resolver los siguientes problemas:

1) Conseguir que el coste de formación de un desarrollador púramente web sea mínimo cuando se deba poner a trabajar con aplicaciones de escritorio.

2) Totalmente multiplataforma, únicamente debemos tener el runtime de AIR instalado en la máquina a ejecutar (linux, windows, iphone…)

3) Crear aplicaciones todo-terreno que sean capaces de ejecutarse tanto como si existe conexión a internet como si no.

4) Dotar a aplicaciones puramente web y desarrolladas con HTML, Ajax, Flex (también de Adobe) o Flash de habilidades púramente de escritorio, como acceso a recursos locales, portapapeles, base de datos local, etc).

A mi en principio me ha dejado algo fuera de sitio la noticia, sobre todo porque sigo creyendo que aquí en España lo normal es que exista mucha más experiencia en desarrollo de aplicaciones de escritorio que aplicaciones web. Es más, lo normal es tener dificultades en encontrar profesionales con experiencia web suficiente… entonces, claro está, la mejora que hemos catalogado como número 1 deja de tener valor.

Sobre la multiplataforma, chapó, está claro que es una ventaja indiscutible.

En cuanto a las aplicaciones todo-terreno, chapó también, ahora veremos qué tipo de aplicaciones son las que realmente le sacan partido a esta particularidad. Tengo verdadera curiosidad en averiguar como gestionan las actualizaciones de las propias aplicaciones instaladas ya en la máquina (que es de los mayores inconvenientes de las aplicaciones instaladas en local).

Aplicaciones web que acceden a recursos locales, suena cuanto menos peligroso, veremos cómo gestionan los permisos.

Me llama sobre todo la atención la posibilidad de combinar Flash y AIR, ya que se permite crear aplicaciones visualmente muy atractivas que permitan además aplicar conceptos avanzados de programación con capacidad además de interactuar contra los recursos de la máquina cliente y contra máquinas remotas.

Dejo links:

http://www.adobe.com/products/air/

Saludos.

Miguel.

Rating 3.00 out of 5
[?]

04.09.08

Mala Definición de la Estructura de un INSERT

Posted in Bases de Datos, Malas Prácticas, Programación at 10:35 pm by Miguel

Esta sentencia SQL es correcta sintácticamente y por tanto ejecutable:

INSERT INTO
COCHE
VALUES
(1, ‘Seat’, ‘IB-4345-CK’, ’12/06/2008′)

Pero tiene un grave problema, no estamos indicando cual es el campo de la tabla donde se va a insertar la información, por lo que por defecto, el sistema gestor de bases de datos pertinente lo asignará a los campos siguiendo el orden en el que fueron creados en la instrucción CREATE TABLE que en su momento se utilizó para dar de alta la tabla en la base de datos.

¿Qué pasa si hago un ALTER sobre la tabla y añado un campo más? Que el INSERT deja de funcionar.

Además, este mal uso es un arma de doble filo porque inicialmente todo funcionará bien, pero de repente, sin saber cómo ni por qué y por “arte de magia” tendremos errores o incosistencias al dar de alta un nuevo coche en nuestro sistema, ya que el orden de los campos habrá cambiado. Si coincide que el campo al que asignamos es del mismo tipo podremos provocar una incosistencia (meter matrículas en el campo donde guardamos la marca del coche), y si no coincide, la base de datos lanzará un error.

Por lo tanto, siempre deberías utilizar la siguiente sintaxis SQL para un INSERT, en lugar de la que especificábamos anteriormente:

INSERT INTO
COCHE
(CO_CODIGO, MARCA, MATRICULA, FECHA_ALTA)
VALUES
(1, ‘Seat’, ‘IB-4345-CK’, ’12/06/2008′)

Saludos.

Miguel.

Rating 3.00 out of 5
[?]

04.07.08

Buenas Prácticas: La Importancia de los Comentarios

Posted in .NET, Buenas Prácticas, Gestión del Mantenimiento, Java, Programación at 8:00 am by Miguel

Poner comentarios en un código siempre se ha considerado por la mayoría como una labor aburrida, tediosa, poco motivante en general.

Luego está el otro extremo, los que se dedican a poner parrafadas de libro en cada línea o en la descripción de los métodos.

Como siempre, los extremos no suelen ser las mejores soluciones. Lo recomendable es siempre comentar, pero a ser posible sin redactar el quijote por cada método o trozo de código. Los comentarios pueden resultar básicos para entender qué está haciendo un determinado algoritmo.

Es algo bastante natural, sobre todo para los programadores con poca experiencia, el tener la creencia de que se van a acordar de lo que hacía el algoritmo, por lo que bajo esa premisa el uso del comentario pierde sentido para ellos. A medida que la experiencia va llegando se llegan a nuevas conclusiones:

1) Como me he encontrado código que no he hecho yo y no está comentado no tengo ni idea de lo que hace. Además, el compañero que lo ha hecho o está a tope y no me lo puede contar o justamente se ha ido una semana de vacaciones. Mira tú por donde esto tiene que estar arreglado esta misma mañana por lo que me voy a tener que quedar comiendo delante del ordenador, así que, la próxima vez que programe algo que no es para mi, lo comentaré, y le diré a mi compañero que haga lo mismo.

2) Estoy solventando una incidencia y recuerdo perfectamente que el código lo hice yo, pero miro y remiro lo que hace y no me acuerdo para nada de por qué tomé esta solución. Es más, no sé ni qué hace o para que sirve esto. Será mejor que comentemos los métodos al crearlos, incluidos los parámetros que se la pasan, así nos evitaremos estos problemas.

3) Mira qué bien, el método está comentado, sé lo que hace por lo que voy a arreglar la incidencia en un momento. El problema viene cuando resulta que alguien cambió el comportamiento del método y no actualizó el comentario, entonces me estoy creyendo que hace lo que dice el comentario… ¿os imagináis el resultado, no? … Está bien, además de añadir un comentario al crear el método, cuando lo modifique también lo ajustaré.

Por ejemplo, trabajando con C# el añadir comentarios a método es muy cómodo, únicamente pulsad tres veces “/” justo en la linea de encima de la definición del método y os aparecerá la estructura xml que tenéis en el método de abajo (sin rellenar claro, la tendréis que rellenar vosotros).

/// <summary>
/// Inserta un nuevo coche
/// </summary>
/// <param name=”codigoCoche”>Identifica de forma única el coche</param>
/// <param name=”nombreCoche”>nombre del coche</param>
/// <param name=”numeroPuertas”>número de puertas del coche</param>
/// <param name=”codigoMarca”>identifica de forma única la marca del coche</param>
public void Insert(int codigoCoche, string nombreCoche, int numeroPuertas, int codigoMarca)
{
 // código necesario para la inserción
}

La buenísima noticia al respecto es que ahora cuando utilicéis el Intellisense de Visual Studio, al seleccionar el método os aparecerán los comentarios que habéis puesto, algo que aumentará vuestra productividad.

Para llevar a cabo la misma acción con VB.NET en lugar de usar “/” tenéis que usar “‘” (comilla simple).

Otra buenísima noticia es que existen herramientas que a partir de los comentarios que añadais a vuestros métodos, clases, interfaces, propiedades generan documentación automáticamente. Los famosos JavaDoc en java son un ejemplo, los archivos .chm para .NET lo mismo.

Saludos.

Miguel.

Rating 3.00 out of 5
[?]

04.06.08

Buenas Prácticas: Uso de Regiones

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

Las regiones son otra herramienta que provee Visual Studio que ayuda a mantener el órden del código, aumentando así su mantenibilidad. Su principal característica es que según pulsas sobre la región esta se muestra o se oculta. Os describo por ejemplo las típicas regiones a usar en una clase.

public class Coche
{

#region Constantes

// codigo que define las constantes #endregion

#region Campos

// codigo que define los campos

#endregion

#region Propiedades

// codigo que define las propiedades

#endregion

#region Constructores

// codigo que define los constructores

#endregion

#region Métodos Públicos

// codigo que define los métodos públicos

#endregion

#region Métodos Protected

// codigo que define los métodos protected

#endregion

#region Métodos Private

// codigo que define los métodos private

#endregion

}

Si tenéis todas las clases estructuradas de la misma manera, encontraréis muy rápido las cosas. Además de que por supuesto la sensación de orden, el trabajar ordenado en sí, es un valor muy importante y que aumentará la mantenibilidad.

Un saludo.

Miguel.

Rating 3.00 out of 5
[?]

« Previous Page« Previous entries « Previous Page · Next Page » Next entries »Next Page »