Amantes de la época de los 8 bits?

Hola!


Quería comentaros que existe una web dedicada a los juegos que se desarrollaron en España durante la época en la que el Spectrum era el ordenador personal más vendido. Esta web, Computer Emuzone, tiene un foro muy activo, y tiene su propio equipo de desarrollo formado por gente entusiasta que dedica horas de su tiempo a desarrollar nuevos juegos para máquinas de 8 bits (Spectrum, Amstrad CPC, MSX) así como Remakes.


Además… Soy miembro del equipo de programación [:$]


Os dejo aquí alguna muestra de lo que se está desarrollando…


Remake del juego de Made In Spain «Sir Fred» (completado)


El Remake del juego de Dinamic «El Capitán Sevilla» (en desarrollo)


Juegos de CEZ GS


Alucino con lo que se puede meter en menos de 48Kb… 😉

Usos interesantes del PropertyGrid

Hola!

Uno de los controles menos utilizados (generalmente) del framework de .NET es el PropertyGrid. Estamos aburridos de verlo, ya que el visor de Propiedades del propio Visual Studio es un PropertyGrid, pero en general pocos son conscientes de que lo pueden utilizar. Este control no es una alternativa a usar pantallas de entrada de datos, pero sí que puede venir bien cuando se tiene que realizar una aplicación interna, como método sencillo para actualizar los objetos que tenemos que manipular.

En este artículo vamos a ver un poco su manejo, y cómo podemos etiquetar mediante atributos las clases para que al mostrarse objetos en el PropertyGrid nos muestren textos de ayuda, el nombre que nosotros queramos, etc…

Los atributos que vamos a utilizar para estos menesteres están definidos en el espacio de nombres System.ComponentModel. Pero lo primero es ver un poco cómo funciona este control. En un formulario, si añadimos un control PropertyGrid, y le asginamos un objeto de una clase cualquiera usando la propiedad SelectedObject, veremos todas las propiedades de dicho objeto. Y para muestra un botón:

Como podemos ver en la imagen, el control extrae todas las propiedades del objeto, y las muestra. Además, nos permite editar los valores, y actualiza el objeto automáticamente. Dependiendo del tipo de datos nos muestra diferentes editores, como un calendario para nuestra propiedad FechaNac, que es de tipo DateTime, o casa de texto para los strings.

Si queremos dar un poco más de información al usuario, podemos utilizar los siguientes atributos:

  • System.ComponentModel.DisplayNameAttribute: Mediante este atributo le indicamos al grid el nombre que debe utilizar para la propiedad a la que se le aplica. Si no se especifica, el control tomará el nombre de la propiedad.
  • System.ComponentModel.DescriptionAttribute: Mediante este atributo le podemos indicar al grid la descripción que mostrará en la parte inferior del control cuando la propiedad esté seleccionada.
  • System.ComponentModel.CategoryAttribute: Mediante este atributo le indicamos la categoría a la que pertenece la propiedad. Por defecto pertenece a la categoría Misc.
  • System.ComponentModel.BrowsableAttribute: Mediante este atributo le indicamos si queremos que sea visible o no en las propiedades. Por defecto es true.

Lo interesante de estos atributos es que no sólo aplican al PropertyGrid, también los utiliza el propio diseñador de Visual Studio, con lo que si los aplicamos a controles de usuario, al utilizarlos en los formularios tendremos las descripciones disponibles, y las categorías que nosotros definamos aparecerán también.

La pinta que tendría después de aplicarle los atributos es la siguiente:

Bueno, pues nada más. En una segunda parte comentaré cómo se pueden crear editores personalizados para las propiedades (y el PropertyGrid), ya que como comprobaréis pronto, si tenéis un objeto con propiedades de un tipo que no tengan editor definido, el PropertyGrid no sabrá qué hacer con ellos [;)]

¡Ojo! Es muy goloso es usar esto para todo… Pero no lo hagáis… Un usuario medio normalmente no sabrá muy bien cómo manejar este engendro, pero sí es muy recomendable si estáis realizando alguna herramienta interna 🙂

Saludos!

El código fuente…

Pórtate bien con tu interfaz de usuario

Hola!

¿Cuántas veces habéis padecido una aplicación que al realizar una operación se queda «tostada»? Me refiero a esas operaciones que llevan un tiempo, transforman tu cursor en un reloj de arena, y cuando minimizas esa ventana (si se deja) y la restauras puedes contemplar el auténtico arte monocromático (es decir, que ves toda la ventana blanca, excepto los bordes).

Ese tipo de comportamientos debería estar prohibido. ¡Pro-hi-bi-do! Sobre todo con lo sencillo que es evitarlo usando .NET. Y este artículo va a explicar qué hemos de hacer para no volver a cometer tropelías del estilo nunca más. [;)]

Cuando en una aplicación estamos ejecutando nuestro código, salvo que creemos hilos, el código se ejecuta sobre el hilo principal de la aplicación. Este hilo principal, si no tocamos el código que genera Visual Studio amablemente, es el encargado de crear nuestras ventanas, nuestros controles, los inicializa, etc. Pero lo que es más importante, en ese hilo principal es donde se ejecuta el bucle de mensajes que mueve toda la maquinaria en las aplicaciones Windows.

Voy a comentar brevemente cómo funciona Windows por debajo de .NET (muy por encima, porque para explicarlo bien, bien, bien, tenéis el fantástico clásico de Charles Petzold, Programming Windows), para que veamos por qué es tan importante el hacer que el hilo principal de ejecución no se quede atascado con operaciones que puedan llevar un tiempo su ejecución.

Básicamente, a diferencia de la programación típica de aplicaciones de consola, el flujo de una aplicación Windows no lo dirigimos nosotros, sino que lo dirige el usuario. Nosotros le exponemos todo aquello que puede manipular (ventanas, botones, cajas de texto, etc), y esperamos a que el usuario interactúe con ellos, para generar una respuesta si nos conviene. Otros mensajes directamente podemos ignorarlos.

Esto se traduce a lo siguiente: Nosotros le pedimos a Windows que nos cree una ventana. Windows nos otorgará una cola de mensajes asociada a la ventana, y cualquier notificación que genere la interacción con el usuario (o procesos internos de Windows) que tengan que ver con nuestra ventana será colocada diligentemente por el sistema operativo en nuestra cola de mensajes. Estos mensajes son de todo tipo, desde «se está moviendo el ratón» a «alguien ha hecho click» o «tienes que repintarte». Hmmm… Todo esto es muy similar a los eventos que conocemos desde hace mucho tiempo antes de .NET (Visual Basic, por ejemplo), ¿verdad?

Volviendo a .NET, cuando creamos un formulario, Windows creará la ventana, y le asocia una cola de mensajes. El hilo principal de ejecución del formulario estará constantemente revisando los mensajes que le envía el sistema operativo, y los traducirá a los eventos que nosotros podemos utilizar en .NET. Cuando llega ese evento, .NET llamará a las funciones que se encarguen de su gestión (Handles o AddHandler en VB.NET, Evento+=new Handler… en C#) en un orden no determinista.

El problema es que las llamadas a nuestros métodos se llevan a cabo de forma síncrona. Esto implica que si tardamos mucho en terminar, el hilo principal no podrá seguir despachando los mensajes. Con lo que no llegan mensajes de «tienes que repintarte», «movieron el ratón», «han hecho click» o «ha pasado x tiempo». Esta es la razón por la que no se puede confiar en los timers para medir tiempo, por ejemplo.

¿Cuál sería la solución? Cuando tengamos una operación pesada en un evento, creamos un nuevo hilo, y ejecutamos la operación de forma asíncrona. Así el método de gestión del evento terminará rápidamente, y todos tan contentos.

Fácil, ¿verdad?

Bueno, esto tiene una pequeña pega. Si durante esa operación que nos hemos llevado a otro hilo tenemos que modificar algún control de usuario, el piñazo está asegurado (se lanzará una InvalidOperationException) ya que en Windows, los controles sólo se pueden modificar desde el mismo hilo en el que fueron creados. Y ese hilo es el principal (en el que NO estamos).

Para solucionar este pequeño problema, los controles y los formularios exponen una propiedad llamada InvokeRequired. Esta propiedad devuelve true si estamos en un hilo diferente al hilo principal, y false en caso contrario. Además, también exponen un método llamado Invoke, que se encarga de ejecutar el método que le indiquemos dentro del hilo principal. O si queremos lanzarlo de forma asíncrona, podemos utilizar el método BeginInvoke.

En el código adjunto podéis ver una aplicación muy sencilla en la que está implementado un ejemplo. El botón Sigues Vivo sirve para ver si se siguen procesando eventos.

Saludos!

Edito: Corregidos un par de fallos ortográficos, y un error de bulto. Caramelo para el que adivine cuál. (NO es en el código).

"UML no sirve para nada" – Reflexiones

En el post menos afortunado de este blog hubo un comentario acerca de UML en el que se aseguraba que UML no vale para nada. Yo contesté que UML no vale para nada si se utiliza mal. Quiero aprovechar para matizar este comentario en este post.


Creo que RUP tiene un problema serio, es demasiado pesado. Y en mi opinión sólo vale para generar toneladas de papel que luego casi nadie se lee. Y si bien la idea de UML de ser una «lingua franca» es interesante, en este tiempo que vivimos, con un auge de las metodologías ágiles, puede parecer un método un tanto draconiano de comunicar las ideas. También es cierto que UML según fue evolucionando se alejó bastante de ser un lenguaje sencillo (con los estereotipos, etc…) Y a día de hoy, alguno de sus creadores reniega de él.


Veo las ventajas que puede tener una metodología ágil en un equipo pequeño, y mucho más si ese equipo está compuesto por programadores muy competentes, ya que eliminar de un plumazo el peso que puede tener una metodología más pesada, en la que se dedica casi más tiempo en generar documentación no entregable que a generar código, es una ganancia de productividad muy interesante. Ojo, que no digo que no haya que generar documentación, y más en un negocio en el que la gente cambia con bastante frecuencia de trabajo, con lo que si no tienes una documentación suficiente, la curva de aprendizaje de una persona que entre para cubrir una vacante será bastante dura de superar.


Lo que no termino de ver es cómo puede encajar una metodología ágil en un proyecto en el que esté involucrado un equipo numeroso de programadores. Cuanto más numeroso es el equipo, más heterogéneo suele ser. Es decir, que las habilidades de los programadores no están equilibradas. En un proyecto de estas características tendrás un equipo de personas que se encarguen de recoger requisitos del cliente, y de alguna forma se tienen que comunicar a las personas que los van a implementar. A ser posible, debería de ser de una forma que sólo tenga una posible interpretación. Y de alguna forma se tiene que planificar o establecer cómo se van a comunicar los diferentes componentes de nuestro sistema, o los diferentes sistemas entre sí.


También he de confesar que las metodologías ágiles no son mi fuerte. De ser así, no tendría las dudas que expongo. Así que aprovecho para lanzar un par de preguntas al aire:



  • ¿Qué libros pueden explicar la problemática expuesta anteriormente? Me refiero a cómo encaja una metodología ágil en un proyecto grande.

  • Ya que UML está condenado, o al menos así parece… ¿Cuáles son las alternativas? ¿Algo similar a UML con colorines como los diagramas de clases de Visual Studio 2005? Creo que estamos todos de acuerdo en que simplemente explicar con palabras la arquitectura de un sistema no sirve, y que es necesario tener algún lenguaje de interpretación única (característica que no posee el lenguaje natural) para poder explicarla. Y lo mismo pasa con muchos otros aspectos, como por ejemplo el despliegue de las aplicaciones, la interacción con el sistema…

  • El hecho de que UML no sirva… No quiere decir que sigamos utilizando aquello que puede ser útil, no? Por ejemplo un diagrama de casos de uso, o diagramas de clases, de estados…

En fin, que estoy pidiendo que me iluminéis… Y que me comentéis vuestras opiniones 🙂

Seguridad en WCF – Mensaje VS Transporte

Hola!


Este artículo tratará de describir las diferentes alternativas que podemos utilizar para aprovechar la seguridad en servicios que nos provee Windows Communication Foundation.


Cuando una aplicación está distribuida, es importante proteger los datos que transmitimos entre los diversos componentes de la aplicación, y las interacciones entre ellos. Es decir, nos interesa que los datos no puedan ser interceptados, modificados, y también el poder controlar quién tiene acceso a la funcionalidad de nuestra aplicación.


Lo que se pretende obtener utilizando seguridad WCF es lo siguiente:



  • Autenticación en el servidor (Service Endpoint Authentication)

  • Autenticación en el cliente (Client Principal Authentication)

  • Integridad de los mensajes

  • Confidencialidad de los mensajes

  • Detección de ataques por repetición (Replay detection): Los ataques por repetición se basan en que un tercero intercepta un mensaje enviado por el cliente al servidor, y vuelve a enviarlo varias veces. (Por ejemplo, peticiones de compra)

WCF trata de obtener dicha seguridad en dos niveles distintos:



  • A nivel de transporte: Es decir, que nos basamos las capas inferiores para proveernos de la seguridad. Esto quiere decir que utilizamos la infraestructura existente para proteger los mensajes. Por ejemplo, utilizar SSL para comunicaciones HTTP, o bien utilizar Kerberos para comunicaciones TCP. WCF se desentiende de proveer confidencialidad, integridad y autenticación. La seguridad empleada depende del transporte que utilicemos, y no está soportado por todos los bindings.

  • A nivel de mensaje: En este nivel, la confidencialidad, integridad y autenticación son provistas directamente por WCF, ya que se incluyen en los mensajes. Para ello, WCF se basa en los estándares WS-Security.

La elección que hagamos en este sentido nos puede impactar en los diferentes bindings que podemos utilizar, ya que no todos soportan uno u otro.


Lo más interesante es que WCF nos permite tomar una alternativa mixta, es decir, utilizar seguridad tanto a nivel de mensaje como de transporte, siempre y cuando el binding que hayamos elegido lo soporte, claro 😉 Si elegimos este escenario, la seguridad a nivel de transporte se encargará de la confidencialidad, integridad y autenticación de las peticiones, mientras que la seguridad a nivel de mensaje se encargará de la autorización. Es decir, en la seguridad a nivel de mensaje es donde especificaremos las credenciales de la manera que más se ajuste a nuestras necesidades utilizando WS-Security, y especificaremos qué operaciones puede realizar un usuario en concreto.


Los tipos de credenciales que se pueden utilizar son los siguientes: 



  • Basic: Se corresponde con la autenticación básica de IIS. Se basa en enviar el par usuario/password al servidor, pero se envía ¡¡¡en texto plano!!!. Cuando se usa este modo, la aplicación deberá estar configurada con una cuenta de usuario concreta que tenga los permisos necesarios para realizar sus tareas.

  • Certificate: El cliente debe utilizar un certificado para autenticarse contra el servidor. Debe establecerse un mapeo entre certificados de cliente y usuarios de Windows en el servidor (se puede hacer con IIS).

  • Digest: Similar a Basic, pero lo que se envía desde el cliente es un Hash de las credenciales. Sigue siendo un sistema débil.

  • Windows: Es similar a la autenticación integrada de Windows que podemos utilizar en IIS. Cuando se utiliza este valor, se supone que el servidor está integrado en un domino que utiliza Kerberos como controlador de dominio. Si el servidor no está basado en Kerberos, o Kerberos falla, se utilizará NTLM.

  • IssuedToken: La autenticación está basada en ADFS. Usa tokens SAML.

Las diferencias más importantes entre ambos tipos de seguridad son los siguientes:



  • La seguridad basada en transporte se lleva a cabo entre cada punto de la conexión. Si la seguridad está basada en mensajes, la seguridad es de extremo a extremo. Es decir, si usamos HTTPS, el mensaje será cifrado y descifrado en cada máquina por la que pase nuestro mensaje, con lo que deberemos confiar en todos los puntos intermedios por los que pasa. Si usamos seguridad basada en mensajes, los únicos que cifrarán o descifrarán el mensaje serán el emisor (que lo cifrará) y el destinatario (que lo descifrará).

  • HTTPS es un protocolo que está implementado en tarjetas, con lo que se puede acelerar por hardware, mientras que la seguridad basada en mensajes puede incurrir en penalizaciones del rendimiento.

  • Desde el punto de vista de la interoperabilidad, la mejor opción a día de hoy sigue siendo usar Web Services «tradicionales» (usando el binding basicHttpBinding) sobre SSL. La razón es sencilla, existen muchas más plataformas que implementan Web Services que plataformas que implementen el estandar WS-Security 😉

  • La seguridad basada en mensajes es muy flexible. Se puede utilizar el tipo de credenciales que se desee, siempre y cuando el cliente y el servidor se pongan de acuerdo.

Pues esto es todo por hoy…


Un saludo!

DataGrid de .NET 1.1 – Cambiando el estilo a las filas

Hola!

Al leer el título, probablemente pensaréis que me he equivocado. Geeks no es precisamente un sitio donde se hable de tecnologías asentadas como .NET 1.1, sino más bien se escribe sobre lo último de lo último. Y es cierto 😉

Pero sin embargo, mucha gente sigue trabajando con .NET 1.1. No todo el mundo puede o quiere migrar a 2.0, pese a que las ventajas son muy interesantes, bien sea por temas de presupuesto, porque el cliente no está dispuesto a asumir el coste de una migración (es un gasto al que un gestor de proyecto no tiene por qué verle las suficientes ventajas), etc.

Hace poco una persona me comentó que no podía cambiar el color de fondo de una fila de un DataGrid en .NET 1.1 en función del valor de uno de los campos de cada fila. Como ese tipo de preguntas son de las que más me estimula (leyendo los dos posts anteriores habréis podido comprobar que soy un poco tocapelotas, pero me gusta bastante ayudar si puedo a la gente), pues me apreté los machos y empecé a indagar cómo se podría hacer.

En .NET 2.0 es bastante sencillo, podemos utilizar la propiedad Rows, que nos devuelve una colección de DataGridViewRow. Una vez tenemos el DataGridViewRow, podemos acceder al elemento enlazado a través de la propiedad DataBoundItem, y podemos modificar el estilo de la fila usando la propiedad DefaultCellStyle. Todo encaja.

Lo primero que pensé fué… Bueno, seguro que no es tan complicado… Voy a la colección Rows del DataGrid, y ahí seguro que puedo cambiarle el BackColor. ¡ERROR! ¡No existe una colección Rows! Ni ninguna que defina las filas del DataGrid desde el punto de vista del interfaz de usuario! (¿Quién diseñó el modelo de objetos del DataGrid de la versión 1.1? ¡Es peor aún que el de Syncfusion!)

Después de andar mirando la documentación un buen rato, y ver que sólo se podían modificar estilos y columnas, decidí tirar por la calle de enmedio. La idea es la siguiente:

  • Heredar de la clase DataGridTextBoxColumn.
  • Sobreescribir el método Paint de la clase.
  • Crear un evento en la clase que pida el color a emplear.

Si lo pensáis, estoy haciendo trampas, porque esto implica que todas las columnas del DataGrid tendrán que ser de esta clase que he creado para que la fila completa aparezca coloreada. Además, dejo como responsabilidad al usuario de la columna el decidir si dicha columna deberá ser coloreada o no. (El código del artículo está disponible en el adjunto).

Al final, el código de la columna era el siguiente: (es VB.NET, que era el lenguaje que me habían pedido utilizar 😛 )

Public Class RowColorEventArgs
    Inherits EventArgs
 
    Public Sub New(ByVal col As color, _
                   ByVal currManager As CurrencyManager, _
                   ByVal rowNum As Integer)
        Me.color = col
        Me.src = currManager
        Me.row = rowNum
    End Sub
 
    Private color As color
    Private src As CurrencyManager
    Private row As Integer
 
    ' Color de la fila.
    Public Property RowColor() As color
        Get
            Return color
        End Get
        Set(ByVal Value As color)
            color = Value
        End Set
    End Property
 
    ' Fuente de datos
    Public ReadOnly Property Source() As CurrencyManager
        Get
            Return src
        End Get
    End Property
 
    ' Indice de la fila.
    Public ReadOnly Property RowIndex() As Integer
        Get
            Return row
        End Get
    End Property
End Class
 
Public Class DataGridColoredTextBoxColumn
    Inherits DataGridTextBoxColumn
 
    Public Event GetForeColor(ByVal sender As Object, _
                              ByVal e As RowColorEventArgs)
    Public Event GetBackColor(ByVal sender As Object, _
                              ByVal e As RowColorEventArgs)
 
    Protected Overloads Overrides Sub Paint(ByVal g As System.Drawing.Graphics, _
              ByVal bounds As System.Drawing.Rectangle, _
              ByVal source As System.Windows.Forms.CurrencyManager, _
              ByVal rowNum As Integer, _
              ByVal backBrush As System.Drawing.Brush, _
              ByVal foreBrush As System.Drawing.Brush, _
              ByVal alignToRight As Boolean)
        Dim evArgs As RowColorEventArgs
        ' Guardamos las brochas para su posterior restauración.
        Dim oldBackBrush As Brush = backBrush
        Dim oldForeBrush As Brush = foreBrush
 
        ' Pedimos el color de fondo
        evArgs = New RowColorEventArgs(Me.TextBox.BackColor, source, rowNum)
        RaiseEvent GetBackColor(Me, evArgs)
 
        ' Creamos la brocha de fondo.
        backBrush = New SolidBrush(evArgs.RowColor)
 
        ' Pedimos el color del texto.
        evArgs = New RowColorEventArgs(Me.TextBox.ForeColor, source, rowNum)
        RaiseEvent GetForeColor(Me, evArgs)
 
        ' Creamos la brocha del texto
        foreBrush = New SolidBrush(evArgs.RowColor)
 
        ' Pintamos
        MyBase.Paint(g, bounds, source, rowNum, _
                     backBrush, foreBrush, alignToRight)
 
        ' Liberamos las brochas! Los recursos de GDI son limitados!
        backBrush.Dispose()
        foreBrush.Dispose()
 
        ' Restauramos las brochas antiguas
        backBrush = oldBackBrush
        foreBrush = oldForeBrush
    End Sub
End Class

La verdad es que no estoy satisfecho con la solución. La cantidad de eventos generados para pintar el DataGrid es enorme. De todas formas, el código para utilizar esta clase, es un poco truculento, y es el que pongo a continuación:

    ' En Form1.vb...
 
    Private Sub Form1_Load(ByVal sender As System.Object, _
             ByVal e As System.EventArgs) Handles MyBase.Load
        Dim tableStyle As New DataGridTableStyle
        tableStyle.MappingName = Me.OrdersDataSet1.Orders.TableName
 
        Me.FillDataSet()
 
        For Each col As DataColumn In Me.OrdersDataSet1.Orders.Columns
            Dim gridCol As DataGridColoredTextBoxColumn = _
                               New DataGridColoredTextBoxColumn
 
            gridCol.MappingName = col.ColumnName
            gridCol.HeaderText = col.ColumnName
 
            AddHandler gridCol.GetBackColor, AddressOf Me.GetBackColor
            tableStyle.GridColumnStyles.Add(gridCol)
        Next
 
        DataGrid1.TableStyles.Add(tableStyle)
        DataGrid1.DataSource = Me.OrdersDataSet1.Orders
 
    End Sub
 
    Private Sub GetBackColor(ByVal sender As Object, _
                             ByVal e As RowColorEventArgs)
        Dim data As DataRowView
        Dim value As Integer
 
        data = CType(e.Source.List.Item(e.RowIndex), DataRowView)
 
        value = CInt(data("EmployeeID"))
 
        If value = 5 Then
            e.RowColor = Color.Red
        End If
    End Sub
 
    Private Sub FillDataSet()
        ' ...
    End Sub

Estoy seguro de que hay una forma más sencilla de hacerlo. ¿Alguien conoce alguna?

La diferencia entre un médico y un informático

Hace poco, mientras jugaba al Trauma Center en la Nintendo DS, me vino a la cabeza uno de esos temas recurrentes que van y vienen de vez en cuando. Ese tema en concreto es la gran diferencia entre un médico y un informático.


Y es que en España, para ser médico tienes que estudiar una carrera de 6 años, hacer una residencia que dura un mínimo de 3 años (según la especialidad) y luego tener suerte y encontrar trabajo o hacer unas oposiciones. Eso quiere decir que para poder ejercer como profesional de la medicina en España (sin contar residencia) es necesaria una formación mínima de 9 años.


Sin embargo, en este mismo país, para ser «informático», pese a tener varias carreras dedicadas a ello, lo único que hace falta es saber programar. O ni eso. Las consultoras de «látigo y remo» pueden coger a cualquier licenciado (o diplomado), les dan un cursillo de 2 a 6 meses (si se lo dan) y… Hala! Ya eres informático. Y además «experto en <ponga usted aquí lo que sea>».


Es decir, en informática tenemos un nivel de intrusismo profesional que dudo mucho que sea igualado por ningún otro sector en este país.


La verdad es que no me pregunto por qué lo tenemos, porque he visto a gente sin carrera picar código de mayor calidad que algunos informáticos con carrera, pero el hecho de ser consciente de esta situación hace que me plantee si no perdí el tiempo estudiando informática por la vía «oficial», en vez de ponerme a trabajar con 18 años. A los 18 años ya llevaba programando 10 años. Empecé con 8 años con el Basic de CPC, de ahí me pasé a los 11 al Pascal porque lo daban en mi colegio, y en casa tenía la suerte de tener un 286 gracias a mis hermanos mayores que estudiaban industriales. Estuve con Pascal hasta los 16, año en que aprendí C, si bien no lo usé en serio hasta la carrera, con 18 años (me gustaba más la legibilidad de Pascal que las llaves de C).


La verdad es que es más sencillo aprender por cuenta propia a programar que a operar… Más que nada porque si metes la pata al programar en casa, el impacto del error es relativamente pequeño.


Pero cuando ya estás en el mundo laboral, te das cuenta de que hay gente programando con orientación a objetos que no tiene ni idea de lo que es una interfaz, de qué es la herencia, el polimorfismo, una clase abstracta… ¡Y son muy felices! Entonces yo me imagino lo que se me pasaría por la cabeza si me tuviesen que operar y me diese cuenta de que el médico que me operará no tiene ni idea de lo que es un bisturí, o unos forceps, o no sabe anatomía. O ves a licenciados en Historia, en Biología o en Pinta y Colorea trabajando de «informáticos». O «analistas» que no tienen ni idea de UML.


Vale, ese es el problema… ¿Y cual sería una solución? Creo que la clave es que los médicos tienen su Colegio de Médicos. Si no estás colegiado, no ejerces. Y lo mismo pasa con los Abogados. Los informáticos… no tenemos. Hay algunas iniciativas de crear Colegios de Informáticos, pero sin tener un Colegio a nivel nacional, que sea lo suficientemente fuerte como para hacer presión, es como si no los tuviésemos. En Castilla y León se creó uno poco después de que terminase la carrera, pero desde entonces (y viviendo ya en Madrid) no he tenido noticias. Así que mucha repercusión no tiene 🙁


Y la pregunta es… ¿A qué estamos esperando? ¿Qué solución le veis a este problema? ¿Realmente es un problema?

Los punteros y la POO (o por qué hay que aprender C)

Quizá un título más apropiado sería ¿qué hace falta para ser un buen programador? 

En el blog de Eugenio Estrada hay un post muy interesante, sobre todo por los comentarios que ha generado. Entre esos comentarios hay opiniones enfrentadas sobre un tema que últimamente levanta ampollas. Si todo el mundo está programando utilizando orientación a objetos, ¿por qué debería la gente aprender C – o Pascal – si luego no lo va a utilizar?

Creo que aprender C (a partir de ahora, cada vez que hable de C, hablo realmente de un lenguaje en el que se puedan utlizar punteros, y que sea estructurado, como puede ser también Pascal) es algo muy necesario para luego entrar de lleno en la orientación a objetos. Y Joel Spolsky también piensa así 😉

El artículo de Joel Spolsky trata acerca de lo que él busca cuando entrevista a gente para formar parte de su plantilla. Es decir, cuenta un poco qué es lo que hace falta para ser un buen desarrollador (según su opinión, que se acerca bastante a la mía). Y para ser un buen desarrollador, sólo hacen falta dos cosas, que son las que busca:

  • Ser inteligente, y
  • Terminar las cosas que se empiezan

Para ayudarle a comprobar el primer punto, en sus entrevistas normalmente suele pedir a los entrevistados que utilizando papel y lápiz hagan un pequeño programa en C con algún algoritmo que requiera el uso de punteros, o de recursión. Y voy a intentar traducir de su artículo el por qué hace eso:

>>15 años de experiencia entrevistando programadores me han convencido de que los mejores programadores tienen una aptitud para manejar varios niveles de abstracción simultáneamente. En programación, esto quiere decir que no tienen problemas con la recursión (en la que tienen que mantener en la cabeza varios niveles de la pila de llamadas a la vez), o en implementar algoritmos complejos basados en punteros (donde la dirección de un objeto es una especie de representación abstracta del objeto).

>>Me he dado cuenta de que entender punteros en C no es una habilidad, sino una aptitud. En el primer año de universidad suele haber unos 200 chavales al principio del semestre, y todos ellos escribieron juegos de aventuras complejos en BASIC para sus PCs cuando tenían 4 años. Pasan un rato divertido aprendiendo C o Pascal en la universidad, hasta que un día el profesor explica los punteros, y de repente no lo entienden. Ya no entienden nada a partir de ese punto. El 90% de los alumnos dejan la clase y se convierten en licenciados en Política, y luego les cuentan a sus amigos que no había los suficientes miembros del sexo apropiado que estuvieran cañón en sus clases de Programación (recordad que la Uni en los USA es diferente, los primeros años son comunes a las especialidades), y que por eso cambiaron de especialidad. Por alguna razón, la mayoría de la gente parece ser que nace sin la parte del cerebro que entiende los punteros. Los punteros requieren una forma compleja de pensar usando una indirección doble que ciertas personas simplemente no pueden hacer, y esa forma de pensar es crucial para poder hacer una programación buena. Muchos de los "script jocks" (no sé cómo traducir esto) empezaron a programar copiando código JavaScript en sus páginas web, y luego aprendieron Perl sin haber aprendido punteros, y no son capaces de producir código con la calidad que necesitas.

Después de leer este artículo (en una versión más antigua), empecé a aplicar esa pequeña prueba en las entrevistas técnicas que tenía que hacer en la empresa en la que trabajaba. Normalmente les pedía a los candidatos que implementasen una función (o un método, ya que yo les dejaba elegir el lenguaje que querían utilizar) que diese la vuelta a una lista enlazada.

  • Muchos de los candidatos (con algún año de experiencia a sus espaldas) se lanzaban a escribir el código directamente, sin ni siquiera hacer un pequeño esquema con la lista enlazada, para hacerse una idea de este puntero que va aquí tiene que ir allí, etc. – picar sin pensar? malo, malo… 
  • Otros directamente no sabían lo que era una lista enlazada, y cuando se lo explicabas, se quedaban perplejos (en ese momento me preguntaba en qué universidad habían estudiado, y si las horas de estructuras de datos las pasaba fumando canutos o jugando al mus).
  • Pero una de las cosas que pude ver es que la mayoría de la gente que elegía hacerlo en Java, VB.NET o C# tenía un serio problema con los constructores de los objetos. Se liaban a rellenar objetos y enlazarlos entre sí. La mayoría de las veces estaban rellenando el mismo objeto una y otra vez, enlazándolo consigo mismo. No eran capaces de entender que lo que manejaban son referencias a objetos.

Sólo uno de los que decidió utilizar C# me sorprendió poniendo: return list.Reverse(); Qué crack 😉 

Un ejemplo de lo que se podría hacer sabiendo utilizar punteros (desde C# y sin usar código unsafe) se puede ver en los comentarios de este artículo de CodeProject.

Hay otra razón de peso para aprender a programar en C antes que en .NET (y ahora hablo únicamente de C). .NET al final es un wrapper construido sobre una API (sea Win32, o sobre las librerías estándar de C en el proyecto Mono). Ese wrapper puede tener bugs (y alguno tiene). Y cuando algo no funciona como es debido en ese wrapper, si no tienes los recursos suficientes para implementar una solución alternativa, lo llevas claro (bueno, más bien oscuro). Interop te puede ayudar, pero no hace milagros. Y si has programado en C para Win32, puedes saber por ejemplo lo que es el bucle de mensajes, y trastear con el WndProc de los controles de .NET. Sí, es raro, y puede que no te vaya a hacer falta… Pero si lo sabes, lo puedes utilizar. Si no… Pues no.

Algunas otras razones hay, como por ejemplo el tener presente siempre la utilización de los recursos (como en C tienes que pedirlos y liberarlos explícitamente, eso siempre ayuda), ya que ciertos recursos son limitados (conexiones a la base de datos, objetos de GDI…) y el no liberarlos correctamente puede hacer que una aplicación se arrastre, o directamente no funcione.

Y si nos vamos a los extremos… Al final el ordenador lo que hace es mover memoria de aquí para allá… 😛

Por último, si quieres ser un buen desarrollador… (esto me fastidia, pero es así) hay que saber inglés. Y muy bien. Aunque gracias a Geeks cada vez hará menos falta.

En fin… ¿Qué opináis vosotros sobre este tema?

ADFS – Configuración de Aplicaciones Web

Hola! Vamos con la segunda parte del artículo que había prometido.


De momento ADFS provee funcionalidad únicamente para aplicaciones web. Para poder autenticar aplicaciones web utilizando ADFS, la instalación nos provee de dos componentes muy importantes:



  • El servicio de autenticación: Este servicio web se encargará de comrpobar los derechos del usuario actual y hacer el mapeo con los derechos que tengamos definidos en nuestro directorio activo. Es el servicio web al que se redirigen las peticiones cuando van acompañadas de una lista de derechos (claims). Es el servicio FederationServerService.asmx que podemos encontrar en la carpeta fs de la instalación.

  • Dos Agentes Web de autenticación: Son dos HttpModule que proveen diferente funcionalidad. Hemos de escoger el que se ajuste más a nuestras necesidades, y deberemos incluirlo en nuestra aplicación para que procese la lista de derechos, de manera que cuando nosotros ejecutemos el código de nuestra aplicación, tengamos disponibles los datos de ADFS a través de la propiedad Identity del objeto User.

Los dos Agentes Web que provee ADFS son los siguientes:




  • Web Agent for Windows NT® Token-based Applications: Este agente crea una sesión de windows para que la aplicación web se pueda impersonar utilizando las credenciales de la sesión creada. Genera un login a partir del nombre de usuario utilizando las extensiones S4U de Kerberos. Las ventajas que nos provee este agente es que podemos utilizar las credenciales del login para pasárselas a diferentes sistemas que requieran autenticación integrada (como por ejemplo un sistema de archivos o SQL Server™). Eso sí, si los recursos son remotos, hemos de habilitar la transición de protocolos en el directorio activo. 


  • Web Agent for Claims-Aware Applications: Este agente no intenta crear una nueva sesión. Lo «único» que hace es pasarnos la lista de derechos del usuario actual dentro del objeto HttpContext.User.

El problema que tiene el primer agente es que tenemos que crear una cuenta en el directorio activo local para cada usuario de los dominios en los que confiamos, con lo que perderemos las ventajas que comentábamos en el artículo anterior. La única ventaja es que los usuarios de los dominios «confiables» no conocen la clave de esta cuenta. De hecho, ni siquiera saben que esa cuenta existe. Pero tendremos que gestionar dichas cuentas, y llegaremos a la inevitable situación de tener usuarios que ya no son necesarios, o de no dar de alta usuarios nuevos de los dominios confiables. 


Por lo tanto, la configuración que vamos a ver es la del agente que nos proporciona la lista de derechos (el segundo, vaya). En este escenario, nuestra aplicación impersonará un usuario genérico (el que nosotros le asignemos, o por defecto NetworkService). Por lo tanto, para dar acceso a los recursos, o para permitir realizar operaciones, tendremos que controlar el acceso explícitamente. Como un ejemplo vale más que mil palabras, vamos a ver cómo podemos acceder a la identidad del usuario actual en nuestra página web. Además, veremos como obtener el valor de un derecho en concreto:


string GetTitle() 
{
    SingleSignOnIdentity id = (SingleSignOnIdentity)User.Identity;
    SecurityPropertyCollection c =
        id.SecurityPropertyCollection.GetCustomProperties(«IdResponsable»);
    return (1 == c.Count) ? c[0].Value : string.Empty;
}

Si nuestra aplicación está basada en Roles, también podemos utilizar ADFS para comprobar si el usuario actual posee un derecho de grupo (group claim). Estos derechos de grupos se pueden consultar utilizando IsInRole, como los roles estándar. 


Por último, cómo configurar la aplicación para que utilice ADFS. Un ejemplo de configuración sería el siguiente:


<configuration>
 
  <!– Añadimos la sección necesaria para la configuración de Single 
       Sign On de ADFS –>
  <configSections>
    <sectionGroup name=»system.web»>
      <section name=»websso» type=
        «System.Web.Security.SingleSignOn.WebSsoConfigurationHandler,
         System.Web.Security.SingleSignOn, Version=1.0.0.0, 

         Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null»/>
         System.Web.Security.SingleSignOn, Version=1.0.0.0, 
         Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null»/>
    </sectionGroup>
  </configSections>
 
  <system.web>
    <!– No utilizamos ninguna de las técnicas estandar de autenticación de 
         ASP.NET, usamos ADFS –>
    <authentication mode=»None» />
    <customErrors mode=»Off»/>
    <sessionState mode=»Off» />
 
    <!– Referencias a los assemblies de ADFS –>
    <compilation debug=’true’ defaultLanguage=’c#’>
      <assemblies>
        <add assembly=»System.Web.Security.SingleSignOn, Version=1.0.0.0,
                       Culture=neutral, PublicKeyToken=31bf3856ad364e35, 

                       Custom=null»/>
                       Culture=neutral, PublicKeyToken=31bf3856ad364e35, 
                       Custom=null»/>
        <add assembly=»System.Web.Security.SingleSignOn.ClaimTransforms,
                       Version=1.0.0.0, Culture=neutral, 

                       PublicKeyToken=31bf3856ad364e35, Custom=null»/>
                       Version=1.0.0.0, Culture=neutral, 
                       PublicKeyToken=31bf3856ad364e35, Custom=null»/>
      </assemblies>
    </compilation>
 
    <!– Cargamos el módulo del agente web de ADFS –>
    <httpModules>
      <add name=»ADFS Web Agent» type=
          «System.Web.Security.SingleSignOn.WebSsoAuthenticationModule,
           System.Web.Security.SingleSignOn, Version=1.0.0.0, 

           Culture=neutral, PublicKeyToken=31bf3856ad364e35, 

           Custom=null» />
           System.Web.Security.SingleSignOn, Version=1.0.0.0, 
           Culture=neutral, PublicKeyToken=31bf3856ad364e35, 
           Custom=null» />
    </httpModules>
 
    <!– Configuración del agente web de ADFS –>
    <websso>
      <authenticationrequired />
      <eventloglevel>55</eventloglevel>
      <auditsuccess>2</auditsuccess>
      <urls>
        <returnurl>https://localhost/miWeb/</returnurl>
      </urls>
      <cookies writecookies=»true»>
        <path>/miWeb</path>
        <lifetime>240</lifetime>
      </cookies>
      <!– Aquí le indicamos donde está instalado el servicio de ADFS –>
      <fs>https://localhost/adfs/fs/federationserverservice.asmx</fs>
    </websso>
  </system.web>
 
  <!– Configuramos las trazas para que sean lo más explícitas posible –>
  <system.diagnostics>
    <switches>
      <add name=»WebSsoDebugLevel» value=»255″ /> 
    </switches>
    <trace autoflush=»true» indentsize=»3″>
      <listeners>
        <!– Para que funcione esto, hemos de crear un directorio C:logs, 
             y hemos de dar permisos  de escritura a la cuenta de sistema 
             NetworkService –>
        <add name=»MyListener» 
             type=»System.Web.Security.SingleSignOn.BoundedSizeLogFileTraceListener,
             System.Web.Security.SingleSignOn, Version=1.0.0.0, 

             Culture=neutral, PublicKeyToken=31bf3856ad364e35, 

             Custom=null»
             System.Web.Security.SingleSignOn, Version=1.0.0.0, 
             Culture=neutral, PublicKeyToken=31bf3856ad364e35, 
             Custom=null»
             initializeData=»c:logsAgenteADFS.log» />
      </listeners>
    </trace>
  </system.diagnostics> 
</configuration>

 

Active Directory Federation Services (ADFS) – Introducción

En MSDN, Keith Brown ha publicado un artículo muy interesante sobre ADFS, visto desde el punto de vista de un desarrollador.

ADFS es la implementación de Microsoft del protocolo WS-Federation, y su funcionamiento se podría resumir muy brevemente de la siguiente manera: cuando un usuario desde una empresa A navega a una aplicación de una empresa B, su navegador es redirigido automáticamente a un sitio web de la empresa A, donde será autenticado. Este sitio le redirigirá de nuevo a la aplicación de la empresa B, pero esta petición irá acompañada de una serie de datos (firmados por la empresa A) que le identifican como un empleado autorizado para usar la aplicación de la empresa B, además de contener una lista de derechos que la empresa A le otorga.

Si bien esta explicación es muy breve, y sin entrar en detalles, lo importante es que la empresa B confía en el acuerdo que tiene con la empresa A, la cual tiene la responsabilidad de autenticar sus propios usuarios. Esta es la idea central de ADFS, que está disponible en Windows Server 2003 R2, y es un sistema que permite que diferentes directorios activos confíen entre sí para autenticar usuarios. Estos directorios activos podrían ser de diferentes departamentos dentro de una empresa, o de diferentes empresas que colaboran entre sí.

Las razones por las que es conveniente tomar este camino son obvias: Reducir la carga de trabajo derivada de mantener la base de datos de usuarios (llamese como se quiera, bien sea directorio activo, una base de datos propia, etc.). Y para muestra un botón:

  • Si el fabricante decide dejar de trabajar con un distibuidor, simplemente tiene que dar de baja al directorio activo de ese distribuidor. En otro caso, tendría que borrar n registros de su base de datos de usuarios (o del directorio activo).
  • Si el distribuidor tiene una baja en sus empleados (bien sea porque cambia de trabajo, o porque le echan, etc), es de suponer que la distribuidora eliminará a dicho usuario de su directorio activo, ya que no le conviene que esa persona tenga acceso a sus aplicaciones, datos, etc. Eso quiere decir que en el momento en el que la distribuidora dé de baja a esa persona, tampoco tendrá acceso a nuestra aplicación. En caso contrario, el distribuidor tendría que avisarnos para eliminar ese usuario de nuestra aplicación (cosa que probablemente no sucedería…)
  • Igualmente, si el distribuidor contrata a nuevos empleados, la situación es muy similar a la del punto anterior. Nos quitamos problemas nosotros y nuestros clientes (toda solución que consigue esto tiene buena pinta, no?)
  • Etc, etc…

Lo más interesante de ADFS es que se basa en un estándar como WS-Federation, que fué diseñado por Microsoft, IBM, Verisign, BEA, y RSA Security. Por lo tanto, como cada empresa puede elegir distinto software para sus servidores, si nosotros utilizamos ADFS, podremos colaborar (en teoría sin problemas) con empresas que utilicen IBM WebSphere o BEA WebLogic, ya que tanto WebSphere como WebLogic implementan WS-Federation.

En dicho artículo usa como ejemplo la creación de una aplicación web de un fabricante de bicicletas que quiere dar acceso a distribuidores autorizados al catálogo de sus productos. Como se quiere evitar tener que crear usuarios para dichos distribuidores en su aplicación (o en su directorio activo), se toma la decisión de utilizar ADFS para autorizar a los usuarios de la aplicación con las credenciales de los directorios activos de las distribuidoras.

Cuando se establece una relación de confianza utilizando ADFS, uno de los directorios activos ha de proveer los usuarios, y otro deberá proveer los recursos. En el caso del artículo, el fabricante de bicicletas provee los recursos (la aplicación web), y los distribuidores proveen los usuarios. Por lo tanto, el fabricante de bicicletas deberá configurar su directorio activo creando un nuevo recurso que represente su aplicación web, y dar de alta a los distribuidores como Account Partners. Los distribuidores darán de alta al fabricante como Resource Partners.

ADFS está basado en una serie de derechos (claims) que cada empresa otrorga a sus empleados. Cada empresa se define su propio conjunto de derechos, y los asigna a sus empleados según sus políticas internas. Esto hace que a primera vista sea complicado la colaboración entre diferentes empresas. Sin embargo, ADFS permite establecer transformaciones de derechos para cada uno de nuestros colaboradores, de manera que cuando un usuario se autentica en su empresa, cuando vuelva a nuestra aplicación su petición viene acompañada por una lista de derechos que le otorga su empresa. Nuestra aplicación no tiene por qué entender dicha lista de derechos, pero ADFS se encarga de buscar las correspondencias adecuadas (si es que las hemos definido), y cuando nuestra aplicación examine los derechos del usuario, será capaz de entenderlos. Lo más interesante es que si un colaborador decide ampliar la lista de derechos, y no nos informan de dicha notificación, nuestra aplicación puede seguir funcionando, siempre y cuando sigan estando definidos los derechos que equivalen a los que nuestra aplicación necesita. Y sin tocar ni una línea de código.

Incluso si los derechos no se pueden transformar mediante configuración, podemos implementar un componente que implemente IClaimTransform. Un ejemplo de una transformación puede ser el decidir si una persona es mayor de edad, ya que el directorio activo sólo almacena la fecha de nacimiento.

Bueno… Por hoy ya es suficiente. En un segundo artículo veremos cómo configurar ADFS para que una aplicación web pueda utilizarlo como método de autenticación.