Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 28 de octubre de 2008
Tanto la guía de programación del lenguaje C# 3.0 como la de Visual Basic .NET 9 hablan de que ambos compiladores pueden agilizar la instanciación de tipos anónimos, permitiendo escribir instrucciones realmente concisas, gracias a su capacidad para deducir los nombres de las propiedades a partir de su contexto. Sin embargo son ese tipo de detalles que, al menos un servidor, había pasado por alto a pesar de haberlo visto utilizado más de una vez.

Como sabemos, la creación "normal" de un objeto de tipo anónimo es como sigue, si lo que queremos es inicializar sus propiedades con valores constantes:
  // C#
var o = new { Nombre="Juan", Edad=23 };

' VB.NET
Dim o = New With { .Nombre="Juan", .Edad=23 }
 
Sin embargo, muchas veces vamos a inicializar sus miembros con valores tomados de variables o parámetros visibles en el lugar de la instanciación, por ejemplo:
  // C#
public void hacerAlgo(string nombre, int edad)
{
var o = new { nombre=nombre, edad=edad };
...
}

' VB.NET
Public Sub HacerAlgo(ByVal nombre As String, _
ByVal edad As Integer)
Dim o = New With {.nombre = nombre, .edad = edad}
...
End Sub
 
Pues bien, es justo en estos casos cuando podemos utilizar una sintaxis más compacta, basada en la capacidad de los compiladores de inferir el nombre de las propiedades del tipo anónimo partiendo de los identificadores de las variables que utilicemos en su inicialización. O en otras palabras, el siguiente código es equivalente al anterior:
  // C#
public void hacerAlgo(string nombre, int edad)
{
var o = new { nombre, edad };
...
}

' VB.NET
Public Sub HacerAlgo(ByVal nombre As String, _
ByVal edad As Integer)
Dim o = New With {nombre, edad}
...
End Sub
 

Brad Wilson, un desarrollador del equipo ASP.NET de Microsoft, nos ha recordado hace unos días lo bien que viene este atajo para la instanciación de tipos anónimos utilizados para almacenar diccionarios clave/valor, como los usados en el framework ASP.NET MVC. También es una característica muy utilizada en Linq para el retorno de tipos anónimos que contienen un subconjunto de propiedades de las entidades recuperadas en una consulta.

Publicado en: www.variablenotfound.com.
domingo, 26 de octubre de 2008
NTraceVamos a continuar desarrollando nuestro traceroute utilizando el framework .NET. En la primera parte del post ya describimos los fundamentos teóricos, y esbozamos el algoritmo a emplear para conseguir detectar la secuencia de nodos atravesados por los paquetes de datos que darían lugar a nuestra ruta.

Continuamos ahora con la implementación de nuestro sistema de trazado de redes.

Lo primero: estructurar la solución

Vamos a desarrollar un componente independiente, empaquetado en una librería, que nos permita realizar trazados de rutas desde cualquier tipo de aplicación, y más aún, desde cualquier lenguaje soportado por la plataforma .NET. Atendiendo a eso, ya debemos tener claro que construiremos un ensamblado, al que vamos a llamar NTraceLib, que contendrá una clase (Tracer) que gestionará toda la lógica de obtención de la traza de la ruta.

Dado que debe ser independiente del tipo de aplicación que lo utilice, no podrá incluir ningún tipo de interacción con el usuario, ni acceso a interfaz alguno. Serán las aplicaciones de mayor nivel las que solucionen este problema. La clase Tracer se comunicará con ellas enviándole eventos cada vez que ocurra algo de interés, como puede ser la recepción de paquetes de datos con las respuestas.

Solución NTrace en Visual Studio 2005Las distintas aplicaciones "cliente" de NTraceLib las crearemos como proyectos independientes:
  • NTrace será una aplicación de consola escrita en C#.

  • WebNTrace, también escrita en C#, permitirá trazar los paquetes enviados desde el servidor Web donde se esté ejecutando hasta el destino.

  • WinNTrace será una herramienta de escritorio, esta vez escrita en VB.NET, que permitirá obtener los resultados de forma más visual.

Tracer: el trazador

La clase Tracer será la encargada de realizar el trazado de la ruta hacia el destino indicado. De forma muy rápida, podríamos enumerar sus principales características:
  • Tiene una única propiedad pública, Host, que contiene la dirección (nombre o IP) del equipo destino del trazado. Los comandos tracert y traceourte tienen más opciones, pero no las vamos a implementar para simplificar el sistema.

  • Tiene definidas también dos constantes:
    • MAX_HOPS, que define el máximo de saltos, o nodos intermedios que permitiremos atravesar a nuestros paquetes. Normalmente no se llegará a este valor.
    • TIMEOUT, que definirá el tiempo máximo de espera de llegada de las respuestas.

  • Publica dos eventos, que permitirán a las aplicaciones cliente procesar o realizar la representación visual de la información resultante de la ejecución del trazado:
    • ErrorReceived, que notificará a la aplicación cliente del componente que se ha producido un error durante la obtención de la ruta. Ejemplos serían "red inalcanzable", o "timeout".
    • EchoReceived, que permitirá notificar de la recepción de mensajes por parte de los nodos de la ruta.

  • El método Trace() ejecutará al ser invocado el procedimiento descrito en el post anterior, lanzando los eventos para indicar a las aplicaciones cliente que actualicen su estado o procesen la respuesta. A grandes rasgos, el procedimiento consistía en ir enviado mensaje ICMP ECHO (pings) al servidor de destino incrementando el TTL del paquete en cada iteración y esperar la respuesta, bien la respuesta al ping o bien mensajes "time exceeded" indicando la expiración del paquete durante la ruta hacia el destino.

Para conocer más detalles sobre la clase Tracer, puedes descargar el proyecto desde el enlace que encontrarás al final del post.

Enviar ICMP ECHOs, o cómo hacer un Ping desde .NET

La versión 2.0 de .NET framework nos lo puso realmente sencillo, al incorporar una clase específicamente diseñada para ello, Ping, incluida en el espacio de nombres System.Net.NetworkInformation. A continuación va un código que muestra el envío de una solicitud de eco al servidor www.google.es:
 Ping pingSender = new Ping ();
PingOptions options = new PingOptions ();
options.DontFragment = true;
byte[] buffer = Encoding.ASCII.GetBytes("datos");
int timeout = 120;
PingReply reply = pingSender.Send ("www.google.es",
timeout, buffer, options);

if (reply.Status == IPStatus.Success)
{
Console.WriteLine ("Recibido: {0}",
reply.Address.ToString ());
}
 
De este código vale la pena destacar algunos detalles. Primero, como podemos observar, existe una clase PingOptions que nos permite indicar las opciones con las que queremos enviar el paquete ICMP. En particular, podremos especificar si el paquete podrá ser fragmentado a lo largo de su recorrido, así como, aunque no aparece en el código anterior, el valor inicial del TTL (time to live) del mismo. Habréis adivinado que este último aspecto es especialmente importante para lograr nuestros objetivos.

Segundo, es posible indicar en un buffer un conjunto de datos arbitrarios que viajarán en el mensaje, lo que podría permitirnos medir el tiempo de ida y vuelta de un paquete de un tamaño determinado. También se puede indicar el tiempo máximo en el que debemos recibir la respuesta antes de considerar que se trata de un timeout.

Por último, la respuesta a la llamada síncrona pingSender.Send(...) obtiene un objeto del tipo PingReply, en el que encontraremos información detallada sobre el resultado de la operación.

Implementación del trazador

Si unimos el procedimiento de trazado de una ruta, descrito ampliamente en el post anterior, al método de envío de pings recién comentado, casi obtenemos directamente el código del método Trace() de la clase Tracer, el responsable de realizar el seguimiento de la ruta:

PingReply reply;
Ping pinger = new Ping();
PingOptions options = new PingOptions();
options.Ttl = 1;
options.DontFragment = true;
byte[] buffer = Encoding.ASCII.GetBytes("NTrace");
try
{
do
{
DateTime start = DateTime.Now;
reply = pinger.Send(host,
TIMEOUT,
buffer,
options);

long milliseconds = DateTime.Now.Subtract(start).Milliseconds;
if ((reply.Status == IPStatus.TtlExpired)
|| (reply.Status == IPStatus.Success))
{
OnEchoReceived(reply, milliseconds);
}
else
{
OnErrorReceived(reply, milliseconds);
}
options.Ttl++;

} while ((reply.Status != IPStatus.Success)
&& (options.Ttl < MAX_HOPS ));
}
catch (PingException pex)
{
throw pex.InnerException;
}
 
Como podemos observar, se repite el Ping dentro de un bucle en el que va incrementándose el TTL hasta llegar al objetivo (reply.Status==IPStatus.Success) o hasta que se supere el máximo de saltos permitidos.

Por cada ping realizado se llama al evento correspondiente en función del resultado del mismo, con objeto de notificar a las aplicaciones cliente de lo que va pasando. Además, se va tomando en cada llamada el tiempo que se tarda desde el momento del envío hasta la recepción de la respuesta. Podéis observar que llamamos al evento EchoReceived siempre que recibamos algo de un nodo, sea intermediario (que recibiremos un error por expiración del TTL) o el destinatario final del paquete (que recibiremos la respuesta satisfactoria al ping), mientras que el evento ErrorReceived es invocado en todas las demás circunstancias. En cualquier caso, siempre enviaremos como parámetros el PingReply, que contiene información detallada de la respuesta, y el tiempo en milisegundos que ha tardado en obtenerse la misma.

Ah, una nota importante respecto al tiempo de resolución de nombres. Dado que la clase Ping funciona tanto si le especificamos como destino una dirección IP como si es un nombre de host, hay que tener en cuenta que el primer ping podrá verse penalizado por el tiempo de consulta al DNS si esto es necesario. Esto podría solventarse muy fácilmente, realizando la resolución de forma manual y pasando al ping siempre la dirección IP, pero he preferido mantenerlo así para mantener el código más sencillo.

Cómo usar NTraceLib en aplicaciones

WinNTraceSea cual sea el tipo de aplicación que vaya a utilizar el componente de trazado, el patrón será siempre el mismo:
  • Declaramos una variable del tipo Trace.
  • Escribimos los manejadores que procesen las respuestas de ErrorReceived y EchoReceived, suscribiéndolos a los correspondientes eventos.
  • Establecemos el host y llamamos al método Trace() del objeto de trazado.
Ya dependiendo del uso que queramos darle a la información recibida, introduciremos en los gestores de eventos más o menos código.

Vamos a ver el ejemplo concreto de la aplicación WinNTrace, sistema de escritorio creado en Visual Basic .NET, que mostrará en un formulario el resultado del trazado. En primer lugar, tiene declarado un objeto Tracer como sigue, lo que nos permitirá enlazarle el código a los eventos de forma muy sencilla:
  Private WithEvents tracer As New Tracer
 
Cuando el usuario teclea un host en el cuadro de texto y pulsa el botón "Trazar", se ejecuta el siguiente código (he omitido ciertas líneas para facilitar su lectura); podréis comprobar que es bastante simple, pues incluye sólo la asignación del equipo de destino y la llamada a la realización de la traza:

tracer.Host = txtHost.Text
Try
tracer.Trace()
Catch ex As Exception
MessageBox.Show("Error: " + ex.Message, "Error", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
 
Cuando se recibe información de un nodo, sea intermediario o el destino final de la traza, añadimos al ListView un nuevo elemento con la dirección del mismo, así como los milisegundos transcurridos desde el envío de la petición:
  Private Sub tracer_EchoReceived( _
ByVal sender As NTraceLib.Tracer, _
ByVal args As NTraceLib.EchoReceivedEventArgs) _
Handles tracer.EchoReceived

Dim items() As String = { _
args.Reply.Address.ToString(), _
args.Milliseconds.ToString()}

Dim item As New ListViewItem(items)
lvResult.Items.Add(item)
Application.DoEvents()
End Sub
 
En el caso de recibir un error, como un timeout, añadiremos la línea, pero aportando mostrando el tipo de error producido y destacando la fila respecto al resto con un color de fondo. Este procedimiento podría haberlo trabajado un poco más, por ejemplo añadiendo textos descriptivos de los errores, pero eso os lo dejo de deberes.
  Private Sub tracer_ErrorReceived( _
ByVal sender As NTraceLib.Tracer, _
ByVal args As NTraceLib.ErrorReceivedEventArgs) _
Handles tracer.ErrorReceived

Dim items() As String = { _
"Error: " + args.Reply.Status.ToString(), _
args.Milliseconds.ToString()}
Dim item As New ListViewItem(items)
item.BackColor = Color.Yellow
lvResult.Items.Add(item)
Application.DoEvents()
End Sub
 
Además de WinNTrace, en la descarga que encontraréis al final del post he incluido NTrace (la aplicación de consola) y WebNTrace (la aplicación web). Aunque cada una tiene en cuenta sus particularidades de interfaz, el comportamiento es idéntico al descrito para el sistema de escritorio, por lo que no los describiremos con mayor detalle.

Conclusiones

WebNTraceA lo largo de estos posts hemos desarrollado un componente de realización de trazados de rutas de red, y tres aplicaciones que lo utilizan. Hemos revisado los fundamentos teóricos en los que se sustenta, y su implementación utilizando .NET framework, siempre con un alcance relativamente simple para facilitar su comprensión.

Dejamos para artículos posteriores la realización de funcionalidades no implementadas en esta versión, como la posibilidad de cancelar una traza una vez comenzada, la resolución inicial de nombres para que el tiempo de respuesta de la primera pasarela sea más correcto, o incluso la resolución inversa del nombre de los nodos de una ruta, es decir, la obtención del hostname de cada uno de ellos tal y como lo hacen las utilidades de línea comand tracert o traceroute. También podríamos incluir funciones de geoposicionamiento de los mismos, para intentar obtener una aproximación la ruta física que siguen los paquetes a través de la red.

Espero que os haya resultado interesante. Y por supuesto, para dudas, consultas o sugerencias, por aquí me tenéis.

Descargar NTrace (proyecto VS2005)

Publicado en: www.variablenotfound.com.
martes, 21 de octubre de 2008
Prototipo en papel de Vimeo.comSaboreando los bocabits ofrecidos por Javier Babuglia encontré, hace ya algo de tiempo, una herramienta de prototipado de interfaces de usuario de lo más útil y simpática, Balsamiq Mockups, que combina la potencia y flexibilidad de un diseñador visual con los resultados del prototipado en papel.

El objetivo de este tipo de herramientas no es obtener el diseño gráfico final de los interfaces de un sistema, sea de escritorio o web, sino un esqueleto o esquema que muestre la disposición conceptual de los principales elementos en pantalla, sin entrar en detalles concretos más cercanos al mundo del diseño artístico.

Su utilización es sencillísima. Contamos con hasta 60 elementos prediseñados que cubren prácticamente todas las necesidades (cuadros, iconos, controles de formularios, textos, etc.) que podemos arrastrar y colocar sobre la superficie de diseño como con cualquier otra herramienta visual, modificando las propiedades (contenido textual, alineación, colores...) de forma directa. El resultado que podéis llegar a obtener es como el mostrado en la siguiente imagen, tomada de los Mockups de ejemplo de la web de sus autores.


Balsamiq Mockups es una aplicación multiplataforma creada con Adobe Flex, de la que existen tanto la versión on-line para usar desde la web, como off-line, para su uso estando desconectado, que se puede descargar de forma gratuita, aunque para acceder a alguna de sus funcionalidades será necesario obtener una clave de licencia, que puede ser gratis si programas por amor al arte (para ONGs, proyectos open source...), o si eres un blogger o escribes en sitios web. En cualquier caso, todo hay que decirlo, la licencia resulta muy económica, menos de 80$.

Y para terminar, ahí va un prototipo de Variable not found realizado en unos minutos:

Variable Not Found, casi en papel

Publicado en: www.variablenotfound.com.
domingo, 19 de octubre de 2008
tracert www.google.es -dSeguro que todos habéis utilizado en alguna ocasión el comando tracert (o traceroute en Linux) con objeto de conocer el camino que siguen los paquetes de información para llegar desde vuestro equipo a cualquier otro host de una red. Sin embargo, es posible que más de uno no haya tenido ocasión de ver lo sencillo que resulta desarrollar un componente que realice esta misma tarea usando tecnología .NET, y lo divertido que puede llegar a ser desarrollar utilidades de red de este tipo.

En esta serie de posts vamos a desarrollar, utilizando C#, un componente simple de trazado de rutas de red. La elección del lenguaje es pura devoción personal, pero lo mismo podría desarrollarse sin problema utilizando Visual Basic .NET. En cualquier caso, el ensamblado resultante podrá ser utilizado desde cualquier tipo de aplicación soportado por el framework, es decir, sea escritorio, consola o web, y, como es obvio, independientemente del lenguaje utilizado para su creación.

Pero comencemos desde el principio...

Un poco de teoría: ¿cómo funciona un traceroute?

El objetivo de los trazadores de rutas es conocer el camino que siguen los paquetes desde un equipo origen hasta un host destino detectando los sistemas intermediarios (gateways) por los que va pasando. La enumeración ordenada de dichos sistemas es lo que llamamos ruta, y es el resultado de la ejecución del comando tracert o traceroute.

Para conseguir obtener esta información, como veremos después, se utiliza de forma muy ingeniosa la capacidad ofrecida por el protocolo IP para definir el tiempo de vida de los paquetes. Profundizaremos un poco en este concepto.

El TTL (Time To Live) es un campo incluido en la cabecera de todos los datagramas IP que se mueven por la red, y es el encargado de evitar que éstos circulen de forma indefinida si no encuentran su destino.

Cuando una aplicación crea un paquete IP, se le asigna un valor inicial al TTL del encabezado del mismo. El valor puede venir definido por el sistema operativo en función del protocolo concreto (TCP, UDP...), o incluso ser asignado por el propio software que lo origine. En cualquier caso, el tiempo se indica en segundos de vida, aunque en la práctica indicará el número de veces que será procesado el paquete por los dispositivos de enrutado que atravesará durante su recorrido.

Cuando este paquete se envía hacia un destino, al llegar al primer gateway de la red, éste analizará su cabecera para determinar su ruta y encaminarlo apropiadamente, y a la misma vez decrementará el valor del TTL. De ahí atravesará otra red hasta llegar al siguiente gateway de su ruta, que volverá a hacer lo mismo. Eso sí, cuando un dispositivo encaminador de este tipo detecte un paquete con un TTL igual a cero, lo descartará y enviará a su emisor original un mensaje ICMP con un código 11 ("time exceed"), que significa que se ha excedido el tiempo de vida del paquete.

El siguiente diagrama muestra un escenario en el que un paquete es enviado con un TTL=3, y cómo es descartado antes de llegar a su destino:

TTL en acción

Volviendo al tema del post y a algo que adelanté anteriormente, el traceroute utiliza de forma muy ingeniosa el comportamiento descrito, siguiendo el procedimiento para averiguar la ruta de un paquete que se detalla a continuación:
  1. Envía un paquete ICMP Echo al destino con un TTL=1. Este tipo de paquetes son los enviados normalmente al realizar un ping a un equipo.
  2. El primer dispositivo enrutador al que llega el paquete decrementa el TTL, y dado que es cero, descarta el paquete y envía el mensaje ICMP informando al emisor que el paquete ha sido eliminado.
  3. El emisor, al recibir este aviso, puede considerar que el remitente del mismo es el primer punto de la ruta que seguirá el paquete hasta su destino.
  4. A continuación, vuelve a intentarlo enviando de nuevo un ICMP Echo al destino, esta vez con un TTL=2.
  5. El paquete pasa por el primer enrutador, que transforma su TTL en 1 y lo envía a la red apropiada.
  6. El segundo enrutador detecta que debe encaminar el paquete y éste tiene un TTL=1 y al decrementarlo será cero, por lo que lo descarta, enviando de vuelta el mensaje "time exceed" al emisor original.
  7. Desde el origen, a la recepción de este mensaje ICMP, se almacena su remitente como segundo punto de la ruta.
  8. Y así sucesivamente, se realizan envíos con TTL=3, 4, ... hasta llegar al destino, momento en el que recibiremos la respuesta a la solicitud de eco enviada (un mensaje de tipo ICMP Echo Reply), o hasta superar el número máximo de saltos que se haya indicado (por ejemplo, usando la opción tracert -h N en Windows)
Según este procedimiento, el pseudocódigo de nuestro sistema de trazado sería algo como el siguiente:
Función Trace(DEST)
Inicio
ttl = 1
Hacer
Enviar ICMP_ECHO_REQUEST al host DEST con TTL=ttl
Si recibimos un TIME_EXCEED desde el host X,
o bien recibimos un ICMP_ECHO_REPLY desde X, entonces
El host X forma parte de la ruta
Fin
Incrementa ttl
Mientras Respuesta <> ICMP_ECHO_REPLY Y ttl<MAXIMO
Fin
 
WinNTraceEn la próxima entrega veremos cómo implementar todo esto en .NET. Concretamente, desarrollaremos un componente que contendrá toda esta lógica, y tres aplicaciones que lo utilizarán: una de consola, una web en ASP.NET y una de escritorio.

Publicado en: www.variablenotfound.com.
jueves, 16 de octubre de 2008
Instalación de ASP.NET MVC BetaTras cinco previews, unas más oficiales y otras menos, por fin se ha publicado la primera Beta del framework ASP.NET MVC.

En un primer vistazo, parece haber pocas novedades importantes respecto a la Preview 5. Además de la corrección de bugs, el documento de notas de la revisión nos indica los siguientes cambios:
  • Cambios en mensajes de validadores para hacerlos más amigables... en inglés, claro.
  • Renombrado de algunos componentes, como CompositeViewEngine
  • Nuevas propiedades que facilitan la composición de URLs desde los controladores.
  • Creación de varias clases para permitir implementaciones personalizadas, como ActionNameSelectorAttribute.
  • Adición de algunos métodos a clases existentes, IViewEngine.ReleaseView.
  • Renombrado de métodos existentes (ControllerBuilder.DisposeController)
  • Cambios de ubicación de la mayoría de métodos de la clase HtmlHelper, que pasan a ser ahora extensiones de dicha clase.
  • Cambio del Model Binder por defecto.
  • Adición de una enumeración con los verbos HTTP más comunes, para usarla en el atributo AcceptVerbsAttribute.
  • Cambio en el método helper RadioButton para permitir el envío de su valor.
  • Se han actualizado las plantillas de proyectos para VS2008.
  • Se ha modificado la forma de seleccionar las acciones a ejecutar, de forma que si dos acciones encajan para ejecutar una petición, aquella que tenga definido un atributo heredando ActionMethodSelectorAttribute, será la invocada.
  • Añadida una sobrecarga para ViewDataDictionary.Eval.
  • Eliminada la propiedad ViewName de la clase ViewContext.
  • Se ha añadido un interface IValueProvider y una implementación por defecto en DefaultValueProvider.

ASP.NET MVC Framework & jQueryEstá claro que el objetivo no ha sido ya la adición de nuevas funcionalidades, sino el testeo y revisión en profundidad de las características desarrolladas hasta el momento, que no son pocas.

Por cierto, y esto sí que representa la materialización de un giro en la política de Microsoft, algo que había comentado por aquí hace unas semanas... ¡ya viene con la librería jQuery incluida en las plantillas de Visual Studio! ASP.NET MVC es, por tanto, el primer producto de la casa que incluye de serie este software, tal y como había comentado Haack poco después de difundirse la noticia.

La instalación, como viene siendo costumbre, resulta de lo más sencilla; el típico siguiente-siguiente-siguiente-finalizar. Eso sí, es conveniente antes de comenzarla desinstalar las versiones anteriores, las previews, en caso de que las tengáis en vuestro equipo.

Publicado en: www.variablenotfound.com.
lunes, 13 de octubre de 2008
Aaarg!Me ha parecido muy interesante y divertido el post de Kevin Pang, "Top 10 Things That Annoy Programmers", en el que obtiene los factores más irritantes para los desarrolladores combinando su propia experiencia con los resultados de una pregunta realizada en StackOverflow, la famosa comunidad de desarrolladores promovida por los populares Joel Spolsky y Jeff Atwood.

Además de estar casi totalmente de acuerdo con los puntos expuestos en su post, que enumero y comento a continuación, añadiré algunos más de propia cosecha de agentes irritantes.
  • 10. Comentarios que explican el "cómo" y no el "qué". Tan importante es incluir comentarios en el código como hacerlo bien. Es terrible encontrar comentarios que son una simple traducción literal al español del código fuente, pues no aportan información extra, en lugar de una explicación de lo que se pretende hacer. Muy bueno el ejemplo de Kevin en el post original... ¿eres capaz de decir qué hace este código, por muy comentado que esté?
    r = n / 2; // Set r to n divided by 2

    // Loop while r - (n/r) is greater than t
    while ( abs( r - (n/r) ) > t ) {
    r = 0.5 * ( r + (n/r) ); // Set r to half of r + (n/r)
    }
     
  • 9. Las interrupciones. Sin duda, el trabajo de desarrollador requiere concentración y continuidad, y las interrupciones son las grandes enemigas de estos dos aspectos. Una jornada de trabajo llena de llamadas, mensajes o consultas de clientes, proveedores, jefes o compañeros puede resultar realmente frustrante, a la vez que la distracción que introduce suele ser una fuente importante de errores en las aplicaciones.


  • 8. Ampliación del ámbito. Una auténtica pesadilla, sobre todo cuando se produce durante el desarrollo, consistente en el aumento desproporcionado del alcance de determinadas funcionalidades o características del software a crear. Es especialmente desmotivador si, además, no viene acompañado por el aumento del tiempo o recursos necesarios para su realización.

    Kevin incluye en su artículo un ejemplo, algo exagerado pero ilustrativo, de sucesivas ampliaciones de ámbito que convierten un requisito factible en un infierno para el desarrollador; seguro que os recuerda algún caso que habéis sufrido en vuestras propias carnes:

    • Versión 1: Mostrar un mapa de localización
      -- Bah, fácil, sólo tengo que crear una imagen; incluso puedo basarme en algún mapa existente que encuentre por ahí

    • Versión 2: Mostrar un mapa 3D de localización
      -- Uff, esto ya no es lo que hablamos; tendré que currarme bastante más el diseño, y ya no será tan fácil partir de alguno existente...

    • Versión 3: Mostrar un mapa 3D de localización, por el que el usuario pueda desplazarse volando
      -- ¡!

  • 7. Gestores que no entienden de programación. Otro motivo común de irritación entre los desarrolladores es la incapacidad de gestores para comprender las particularidades de la industria del software en la que trabajan. Este desconocimiento genera problemas de todo tipo en una empresa y suponen un estrés terrible para el desarrollador.


  • 6. Documentar nuestras aplicaciones. Lamentablemente, en nuestro trabajo no todo es desarrollar utilizando lenguajes y tecnologías que nos divierten mucho. Una vez terminado un producto es necesario crear guías, manuales y, en general, documentación destinada al usuario final que, admitámoslo, nos fastidia bastante escribir.


  • 5. Aplicaciones sin documentación. A pesar de que entendamos y compartamos el punto anterior, también nos fastidia enormemente tener que trabajar con componentes o librerías partiendo de una documentación escasa o nula. Si lo habéis sufrido, entenderéis lo desesperante que resulta ir aprendiendo el significado de las funciones de un API usando el método de prueba y error.


  • 4. Hardware. Especialmente los errores de hardware que el usuario percibe como un fallo de la aplicación son normalmente muy difíciles de detectar: fallos de red, discos, problemas en la memoria... por desgracia, hay un amplio abanico de opciones. Y lo peor es que por ser desarrolladores de software se nos presupone el dominio y control absoluto en asuntos hardware, lo que no siempre es así.


  • 3. Imprecisiones. Aunque Kevin lo orienta al soporte al usuario, el concepto es igualmente molesto en fases de diseño y desarrollo del software. Las descripciones vagas y confusas son una causa segura de problemas, sea en el momento que sea.

    Son irritantes las especificaciones imprecisas, del tipo "esta calculadora permitirá al usuario realizar sumas, restas, multiplicaciones y otras operaciones"... ¿qué operaciones? ¿divisiones? ¿resolver ecuaciones diferenciales?

    Tampoco es fácil encajar un mensaje de un usuario tal que "me falla el ERP, arréglalo pronto"... A ver. El ERP tiene cientos de módulos, ¿fallan todos? ¿podríamos ser más concretos?


  • 2. Otros programadores. Como comenta Kevin, el malestar que provoca a veces la relación entre programadores bien merecería un post independiente, pero ha adelantado aspectos que, en su opinión, hace que a veces el trato con los compañeros sea insoportable:

    • Personalidad gruñona, hostilidad
    • Problemas para comprender que hay que dejar de debatir la arquitectura del sistema y pasar a realizar las tareas
    • Falta de habilidad para mantener una comunicación efectiva
    • Falta de empuje
    • Apatía hacia el código y el proyecto


  • 1. Tu propio código, 6 meses después. Sí, es frustrante estar delante de un código aberrante y darte cuenta de que tú eres el autor de semejante desastre. Y tras ello llega la fase de flagelación: ¿en qué estaba pensando cuando hice esto? ¿cómo fui tan estúpido? uff...

    Este hecho, sin embargo, forma parte de la evolución tecnológica, personal y profesional; todos estos factores están en continuo cambio, lo que hace que nuestra forma de atacar los problemas sea distinta casi cada día.

Siempre acaba pagándola el más tonto...Y hasta aquí la lista de Kevin en su post, ni que decir tiene que comparto sus reflexiones en la mayoría de los puntos. Por mi parte, añadiría los siguientes agentes irritantes que conozco por experiencia propia o de conocidos:
  • Extra 1. Requisitos evolutivos, como una ampliación del ámbito del punto 8 ;-), que son aquellos que van cambiando conforme el desarrollo avanza y que obligan a realizar refactorizaciones, descartar código escrito, e introducir peligrosas modificaciones, afectando a veces por debajo de la línea de flotación del software. Más rabia produce, además, cuando se atribuyen una mala interpretación por parte del desarrollador de una especificación imprecisa.

  • Extra 2. Problemas en el entorno. Nada más frustrante que cortes en el suministro eléctrico, cuelgues, problemas en el hardware, lentitud en los equipos de trabajo o de acceso a información... a veces parece que tenemos que construir software luchando contra los elementos.


  • Extra 3. El "experto" en desarrollo de software. Clientes, gestores y otros individuos que utilizan frecuentemente, y sin conocimiento alguno de causa, expresiones como "Esto es fácil", "Una cosa muy sencilla", "¿Eso vas a tardar en hacer esta tontería?".... A veces no es fácil hacer entender que la percepción externa de la complejidad es absolutamente irreal, y suele ser una causa frecuente de desesperación para los desarrolladores.


  • Extra 4. Usuarios corrosivos, que lejos de colaborar durante el desarrollo o la implantación de un sistema, aprovechan la ocasión para arremeter contra la aplicación, organización, jefes, compañeros, el gobierno, o lo que se ponga por delante. Es de justicia decir que muchas veces este comportamiento es debido a una mala gestión interna del proyecto, pero desde el punto de vista del profesional del sofware que sólo quiere realizar lo mejor posible su trabajo son una auténtica pesadilla.


En fin, que ya a estas alturas es fácil ver que hay bastantes cosas que fastidian a los desarrolladores, y seguro que podríamos añadir muchas más; algunas son evitables, otras son inherentes a la profesión y hay que aprender a convivir con ellas, pero en cualquier caso son un interesante motivo de reflexión.

¿Y a tí, qué es lo que más te fastidia?

Enlace: Top 10 Things That Annoy Programmers
Publicado en: www.variablenotfound.com.
martes, 7 de octubre de 2008
A veces puede resultar interesante acceder desde una página de contenidos a propiedades de su página maestra. Hoy he encontrado un truco para conseguir este acceso con la seguridad que proporciona un tipado fuerte.

Como sabemos, la propiedad Master de las páginas de contenidos, a través de la cual es posible acceder a la página maestra, es por defecto del tipo MasterPage. Esto es así porque todas las masters que creamos heredan de esta clase, y es una abstracción bastante acertada la mayoría de las veces. De hecho, es perfectamente posible hacer un cast al tipo correcto desde el código de la página para acceder a alguna de las propiedades públicas que le hayamos definido, así:

protected void Page_Load(object sender, EventArgs e)
{
MaestraContenidos master = Master as MaestraContenidos;
master.Titulo = "Título";
}
 
Pues bien, mediante la directiva de página MasterType es posible indicar de qué tipo será esta propiedad Master, de forma que no será necesario hacer el cast. En la práctica, en el ejemplo anterior, podríamos hacer directamente Master.Titulo="Título", sin realizar la conversión previa.

La directiva podemos utilizarla en el archivo .ASPX, haciendo referencia al archivo donde está definida la página maestra cuyo tipo usaremos para la propiedad:

<%@ MasterType VirtualPath="~/site1.master" %>
 
O también podemos hacerlo indicando directamente el tipo (ojo, que hay que incluirlo con su espacio de nombres completo):

<%@ MasterType TypeName="ProyectoWeb.MaestraContenidos" %>
 

Por último, algunas contraindicaciones. Si váis a usar esta técnica, tened en cuenta que:
  • si decidís cambiar la página maestra en tiempo de ejecución, en cuanto intentéis acceder a la propiedad Master, vuestra aplicación reventará debido a que el tipo no es el correcto.

  • si cambiáis la maestra a la que está asociada una página de contenidos, tenéis que acordaros de cambiar también la directiva MasterType de la misma para que todo funcione bien.


Publicado en: www.variablenotfound.com.