miércoles, 31 de diciembre de 2008

Propósitos para 2009

Como siempre que se acaba algo es bueno echar la vista atrás y hacer un poco de reflexión de cómo ha sido el año, personalmente el 2008 ha sido decepcionante en algunos aspectos, vamos que no será un año que recuerde con nostalgia, pero no quiero ser pesimista (mi carácter me lo impide) y tengo que reconocer que este año he sacado unas cuantas buenas experiencias que merecieron la pena ser vividas :)

Y como cada vez que se empieza algo, también es bueno tener un plan, por pequeño que sea, de cómo nos gustaría hacer las cosas, así que hay van mis propósitos para 2009:

En lo personal, intentar ser feliz, que con la que está cayendo creo que ya es bastante. Y disfrutar un poco más de la vida, ser un poco más irresponsable y hacer las cosas que me apetece hacer antes de las que “debería” hacer.


En lo profesional:

  • Darle un poco de caña al tema web, que lo tengo bastante abandonado desde hace tiempo y siempre es bueno cambiar de chip de vez en cuando y actualizarse un poco.
  • Poner en práctica las cosas nuevas que he aprendido este año, como SCRUM.
  • Mantenerme al día de las novedades que vayan apareciendo en .NET (.NET 4.0 y VS 2010 ya están a la vuelta de la esquina), pero sin volverme loco, que para estar al corriente de todo hay que ser un super-desarrollador :P
  • Intentar escribir cosas más interesantes en el blog, que lo tengo un poco abandonado pero ganas no me faltan.
  • Seguir aprendiendo cosas nuevas, que aunque no tengan que ver directamente con el trabajo, siempre aportan algo.

Seguro que cuando vaya avanzando el 2009 mis prioridades irán cambiando, como siempre lo afronto con ilusión y ganas, a ver qué tal sale todo :)

FELIZ AÑO A TOD@S y happy codding ;)

martes, 30 de diciembre de 2008

Problema (y solución) al instalar .NET Framework 3.5 (V)

Seguimos con errores al instalar el .NET Framework 3.5 SP1, esta vez se trata de un Windows XP SP2 que, aparentemente, no tienen ningún .NET Framework instalado:


[XX/XX/08,16:24:15] RGB Rast: [2] Error: Installation failed for component RGB Rast. MSI returned error code 1625
[XX/XX/08,16:24:30] WapUI: [2] DepCheck indicates RGB Rast is not installed.

Intentamos instalar manualmente el componente RGB RAST pero se produce el siguiente error:

MSI (s) (9C:AC) [16:26:53:437]: Machine policy value 'DisableUserInstalls' is 0
MSI (s) (9C:AC) [16:26:53:453]: File will have security applied from OpCode.
MSI (s) (9C:AC) [16:26:53:453]: SOFTWARE RESTRICTION POLICY: Verifying package --> 'C:\dotnetfx30\RGB9RAST_x86.msi' against software restriction policy
MSI (s) (9C:AC) [16:26:53:453]: SOFTWARE RESTRICTION POLICY: C:\dotnetfx30\RGB9RAST_x86.msi has a digital signature
MSI (s) (9C:AC) [16:26:53:531]: SOFTWARE RESTRICTION POLICY: SaferComputeTokenFromLevel reported failure. Assuming untrusted. . . (GetLastError returned 1260)
MSI (s) (9C:AC) [16:26:53:531]: La instalación de C:\dotnetfx30\RGB9RAST_x86.msi no está permitida debido a un error en el proceso de directiva de restricción del software. No hay confianza en el objeto.
MSI (s) (9C:AC) [16:26:53:531]: Note: 1: 1718 2: C:\WINDOWS\Installer\1b5ea04.msi
MSI (s) (9C:AC) [16:26:53:531]: MainEngineThread is returning 1625
MSI (c) (74:88) [16:26:53:640]: Decrementing counter to disable shutdown. If counter >= 0, shutdown will be denied. Counter after decrement: -1
MSI (c) (74:88) [16:26:53:640]: MainEngineThread is returning 1625


Como os podéis imaginar, en las políticas de restricción de software del equipo no había ABOSLUTAMENTE NADA!!! Tenía permisos de administrador pero por algún motivo no me dejaba instalar un componente de la propia Microsoft.


Buscando un poco encuentro la solución en esta página: http://support.microsoft.com/kb/925336 que consiste en:


1. Haga clic en Inicio y en Ejecutar, escriba regedit y haga clic en Aceptar.


2. En el Editor del Registro, busque la clave siguiente y después haga clic en ella:
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Safer\CodeIdentifiers

Nota: antes de modificar la clave, recomendamos que haga un copia de seguridad. Para ello, haga clic con el botón secundario en CodeIdentifiers y, a continuación, haga clic en Exportar. Guarde el archivo en una ubicación donde pueda buscarlo en el equipo.

3. Cambie el valor del Registro PolicyScope. Para ello, haga doble clic en PolicyScope y, a continuación, cambie la configuración de 0 a 1.

4. Cierre el Editor del Registro.

5. Haga clic en Inicio y en Ejecutar, escriba cmd y, a continuación, haga clic en Aceptar para abrir una ventana de símbolo del sistema.

6. En el símbolo del sistema, escriba el comando siguiente y presione ENTRAR:

net stop msiserver

Este comando detiene el servicio Windows Installer si se está ejecutando actualmente en segundo plano. Cuando el servicio se haya detenido, cierre la ventana de símbolo del sistema y, a continuación, vaya al paso 7.

Nota: si recibe el mensaje siguiente en el símbolo del sistema, cierre la ventana de símbolo del sistema y, a continuación, vaya al paso 7: El servicio Windows Installer no se inicia

7. Instale el paquete que estaba intentando instalar cuando recibió el mensaje de error que se menciona en la sección "Síntomas".

8. Después de instalar el paquete, repita los pasos 1 y 2. A continuación, vuelva a establecer el valor del Registro PolicyScope en 0.

9. Si desconectó el equipo de un dominio, vuelva a unirse al dominio y, a continuación, reinicie el equipo.Nota: si no desconectó el equipo de un dominio, no tiene que reiniciarlo.

Lo curioso del tema es la posible explicación que dan, que dice algo como: “Si un archivo de paquete .msi o .msp es demasiado grande para caber en una parte contigua de memoria virtual, Windows Installer no puede comprobar que el paquete es correcto.”

Y claro, en vez de decir que no puede instalarlo porque no tiene memoria virtual suficiente, pues nos dice que no tenemos permisos porque hay una política de restricción de software que lo impide, todo muy coherente, sí señor ¬¬


Volviendo al tema, una vez modificada la entrada en el registro, se intenta la instalación, pero vuelve a fallar, esta vez con el error :


[09/03/08,11:30:32] Microsoft .NET Framework 2.0a: [2] Error: Installation failed for component Microsoft .NET Framework 2.0a. MSI returned error code 1603
[09/03/08,11:32:03] WapUI: [2] DepCheck indicates Microsoft .NET Framework 2.0a is not installed.

Este ya es un error conocido, y lo solucioné como otras veces: Problema (y solución) al instalar .NET Framework 3.5 (II)

Relacionado:
Problema (y solución) al instalar .NET Framework 3.5 (I)
Problema (y solución) al instalar .NET Framework 3.5 (II)
Problema (y solución) al instalar .NET Framework 3.5 (III)
Problema (y solución) al instalar .NET Framework 3.5 (IV)

jueves, 6 de noviembre de 2008

Try ...Catch y RAISERROR en T-SQL: ¿es un bug o una feature?

No voy a entrar a explicar cómo se usan los bloques Try...Catch en T-SQL, que para eso ya está el MSDN: http://msdn.microsoft.com/es-es/library/ms179296(SQL.90).aspx

si no que os voy a contar un caso curioso que nos ha pasado estos últimos días:

Tenemos una aplicación en VB 6.0 (sí, tiene que ser en VB 6.0 por narices, así que es lo que hay) que tiene que llamar a store procedures de una base de datos SQL Server 2005 usando ADO (sí, el clásico no el .NET), bueno, el caso es que en algunos store procedures tenemos algo parecido a esto:


CREATE PROCEDURE Mi_Procedure
AS
BEGIN
BEGIN TRY
... Código antes del RAISERROR
RAISERROR(...) -- Este RAISERROR provoca que se vaya al bloque CATCH
... Código después del RAISERROR que no se ejecuta
END TRY
BEGIN CATCH
Exec Otro_Procedure @parametro1, @parametro2
RAISERROR(...) -- Este RAISERROR debería propagar el error al que ha llamado al store procedure
END CATCH
END


Bien, es algo bastante básico, pero lo curioso del tema es que tal y como está, desde ADO no se captura el error, ni se dispara un error interceptable ni está en la colección de errores de la conexión.

Investigando un poco descubrí que en Otro_Procedure que se llama desde aquí había una llamada a sp_executesql y esto provoca que por algún motivo se genere un entorno de ejecución diferente, lo que a su vez provoca que el ADO no capture el error.

¿Cuál puede ser la solución?
Teniendo en cuenta que no podíamos obviar la llamada a Otro_Procedure y tampoco a sp_executesql se me ocurrió la idea de darle la vuelta al bloque CATCH y hacer el RAISERROR antes de la llamada a Otro_Procedure. La idea parece un poco absurda si pensamos que el bloque TRY...CATCH funcionase como, por ejemplo, en C#, pero aquí viene el origen del post, el bloque TRY...CATCH en T-SQL te permite ejecutar cualquier instrucción después de hacer un RAISERROR.

O_o

¿¿¿ Eing???

Pues sí, la lógica dice que en un CATCH cuando hagas un RAISERROR este se propagará hacia arriba hasta llegar al llamador del procedure, pero la implementación en T-SQL hace que esto no sea así y que no se finalice la ejecución hasta llegar al END CATCH, con lo que después del RAISERROR podemos poner la/s instrucciones que queramos que se van a ejecutar.

Por supuesto, haciendo la misma llamada al store procedure desde .NET con ADO.NET siempre se intercepta el error, esté el RAISERROR del CATCH antes o después de la llamada a Otro_Procedure, con lo que +1 para ADO.NET :)

Happy coding ;)

jueves, 9 de octubre de 2008

Con ofertas como esta dan ganas de dejar de trabajar

Iba a empezar el post diciendo algo como “Leo sorprendido en Halón Disparado una oferta de trabajo...” pero la verdad es que me di cuenta que no me sorprendió tanto, debe ser que de ver cosas como esta te acabas curtiendo.


Para el que no vea bien la imagen os lo transcribo, se trata de una oferta para un desarrollo en Argentina con las siguientes condiciones:


Busco desarrollar lo siguiente:
Un Panel de control para un sitio web de una inmobiliaria, solamente el desarrollo del panel y la base de datos ya que el diseño corre por nuestra cuenta:


- Debe poder soportar múltiples usuarios (con diferentes perfiles – administrador y empleados-)
- Se debe poder cargar los inmuebles de las propiedades conectando con una base de datos mysql
- Las imágenes de los inmuebles se deben guardar en una carpeta del servidor
- Se debe poder destacar las imágenes para que puedan aparecer en el index.php como imágenes destacadas
- Debe poseer diversos parámetros: cantidad de habitaciones, superficie, precio, dirección, provincia, ciudad y observaciones adicionales.
- Debe poseer una interfaz de carga ágil, dinámica y sencilla de entender.
- Debe poseer un buscador interno de propiedades con varios parámetros de búsqueda.
- Debe poseer un ABM de propiedades, entendible.
- Se debe confeccionar manual de operaciones del panel de control


Bien, son una serie de requerimientos bastante imprecisos para un desarrollo de algo tan complejo, pero lo mejor viene con las condiciones de la oferta:

Tiempo de entrega: 15 días
Presupuesto: 200,00 ARS (46,72 EUR)

Ante esto sólo me vino una cosa a la mente WTF!!! Es que estamos tontos o qué es lo que pasa. Vale que haya una acuciante crisis mundial (sinceramente yo ni me he enterado, pero bueno es lo que tiene no tener dinero para invertir :P) pero es que ese presupuesto no se le puede considerar un sueldo, es poco menos que una propina :(

¿En serio piensan que alguien en su sano juicio desperdiciará 15 días de su vida por menos de 50 €? 46,72 € /15 días = 3,11 €/día!!!!! Vamos, que no te da ni para pagarte un desayuno.

¿En qué clase de mundo vive el que hace esta oferta? Seguro que piensa que hay algún desarrollador web por ahí que tiene algo parecido ya hecho y no le importa venderlo, pero ¿alguien vendería su trabajo por esa miseria?


Mientras escribo el post me he vuelto a leer la oferta y me llaman la atención un par de cosas más:

- Al principio de la oferta dicen que ya se encargarán ellos del diseño (¿buscarán un diseñador que se lo haga por 20 €?) pero también piden que tenga “una interfaz de carga ágil, dinámica y sencilla de entender”. Y digo yo, la interfaz y el diseño como que van bastante de la mano, así que la mayor parte de SU trabajo ya estaría hecho, ¿no?


- Me encanta como describen lo que tiene que convertirse en el diseño de la base de datos: “Debe poseer diversos parámetros: cantidad de habitaciones, superficie, ...” Y el resto te lo inventas que para eso te pagamos un pastón.


- Dicen que “las imágenes se deben guardar en una carpeta en el servidor”, que seguro que llegan allí por arte de magia y se relacionan con los inmuebles por telepatía.


- Buscador interno, múltiples usuarios, ... vamos lo normal, pero lo mejor es que “Se debe confeccionar manual de operaciones”, claro que sí, y en varios idiomas y todo. Y aún querrán los fuentes y que les des mantenimiento de la aplicación 24 horas/365 días, como si lo viera.

Tengo que reconocer que en mientras estudiaba aproveché que teníamos que hacer un proyecto de tienda virtual (o e-commerce que mola más) para una asignatura y con un compañero se lo “vendimos” a una tienda real (de cómics, juegos de rol, y frikadas varias) y no le cobramos nada.

Pero es que a mí personalmente me sirvió de mucho ya que teníamos que hacerlo de todas formas para la asignatura y así aprendimos lo que es una implantación real y los problemas que plantea. Pero lo de esta oferta es de juzgado de guardia, no sólo quieren que algún pobre desgraciado les haga un proyecto bastante complejo (porque son muy listos y la mitad de las cosas obvias que hay que hacer no las ponen como requerimientos) en 15 días, si no que quieren pagar una auténtica miseria por ello.

Espero que todo esto se trate de un error al poner el presupuesto, porque de ser real esta gente piensa que los desarrolladores somos completamente estúpidos :( Lo malo es que se trate o no de un error existe gente que piensa así, y que nuestro trabajo no vale el precio que le ponemos porque total, ya está todo hecho.

PD: No sé qué es un ABM, si alguien lo sabe por favor que me lo diga por si acaso algún cliente me lo pide algún día y así no me quedo con cara de tonto.

PD2: He puesto esta entrada en la categoría de Humor porque es mejor no tomarse estas cosas en serio.

miércoles, 1 de octubre de 2008

.NET Framework 4.0 y Visual Studio 10: que paren que yo me bajo

Leo en varios blogs como este, o este otro (en inglés) o la nota de prensa oficial (también en inglés) la noticia de que los chicos de Microsoft ya tienen bastante definidos lo que será el próximo .NET Framework (y ya vamos por el 4.0) y la nueva versión de Visual Studio (que como siempre van de la mano).

No me voy a parar en comentar las novedades que prometen porque ya hay un montón de gente que sabe más que yo de esto que lo están haciendo, pero el hecho de que salga la noticia me plantea un par de preguntas que lanzo al aire:

  • ¿Por qué pasa tan poco tiempo entre una versión y la siguiente?
  • ¿Son imprescindibles los cambios que aportan las nuevas versiones? ¿Los vamos a usar al 100%? ¿Alguien los va a llegar a usar todos o una gran parte de ellos?
  • ¿Acabamos los desarrollos que tenemos entre manos con la versión actual o nos conviene esperar a las novedades de la nueva? ¿Sacamos una nueva versión cuando salga el nuevo Framework?
  • ¿Alguien es capaz de seguir este ritmo? ¿Estamos locos los desarrolladores?


Cuando mucha gente aún no se ha pasado a la versión 3.5 del .NET Framework, se encuentran con que ya está prevista la 4.0, cosa bastante natural con la forma de trabajar de Microsoft. Pero es que hay que recordar que el .NET Framework sólo lleva entre nosotros desde 2002, con lo que tenemos que en 6 años han aparecido 5 versiones (1.0, 1.1, 2.0, 3.0 y 3.5), casi a versión por año (y eso sin contar con los Service Packs).


¿Qué aportaron estas nuevas versiones en su momento? Recordando así por encima, la 2.0 aportó bastantes mejoras en el Framework, sobre todo en ADO.NET y ASP.NET. La 3.0 nos introdujo WCF, WF, WPF y esa cosa que llamaron CardSpace pero que no he visto funcionando en ningún sitio. Y la 3.5 es una revisión de la 3.0 y además nos trae LINQ y en paralelo apareció Entity Framework.


Tanto la nueva versión del .NET Framework como la del Visual Studio prometen lo de siempre: mejorar la vida de los desarrolladores para que podamos crear aplicaciones de gran calidad en el menor tiempo posible. Vaya, pues si es así lo quiero YA!!!


Pero es esto que se llama la Vida Real™ los pobres curritos-pica-código nos encontramos con que la mayoría de “mejoras” no nos servirán absolutamente para nada cuando tenemos el plazo de finalización del proyecto echándonos el aliento en la nuca (que mal rollo que da esa frase :P) y los pocos que nos servirían implican cambiar tantas cosas que tendríamos que modificar la mitad del proyecto o empezarlo casi de 0, porque, reconozcámoslo, nunca se hacen las cosas tan bien que sean totalmente reutilizables.


Después están los que lo prueban todo, desde las versiones alfa, y ya empiezan los nuevos proyectos con las nuevas versiones cuando no han ni empezado a asomarse. Pero yo creo que esa gente no es de este planeta, porque entre el tiempo que dedican al trabajo, el de probar las nuevas versiones, escribir en diferentes blogs, leer lo que escriben los demás, preparar podcast, webcast y presentaciones,... a mí no me quedaría tiempo para casi nada, así que me imagino que o no comen, o no duerme o tienen un reloj que les permite viajar en el tiempo. O tal vez sus horas tienen 99 minutos porque encontraron un bug en el sistema horario.


Menos mal que estos son 4 elegidos por el ente supremo (llámalo Dios o el monstruo espagueti volador) porque si no todos los que nos dedicamos a esto y no tenemos sus superpoderes nos quedaríamos en el paro. Porque últimamente es muy pero que muy complicado ser desarrollador en .NET y no morir bajo la avalancha de novedades que nos llega casi sin avisar.

Así que creo que para los simples mortales nos quedan 3 opciones claras:



  • Dejar la programación y dedicarnos al cultivo del tomate (así por lo menos tendremos algo que comer)

  • Detenernos en una versión y meternos en una cueva aislada del mundo hasta finalizar nuestros proyectos.

  • Echarle ... narices e intentar mantenernos al día de todas las novedades, pero sin perder la perspectiva de que hay que acabar los proyectos porque hay jefes/clientes que esperan las cosas para ayer. O casi mejor al revés (más que nada para que no nos despidan), finalizar nuestros proyectos pero sin perder de vista las novedades y las futuras versiones.

Ahora es decisión vuestra como desarrolladores elegir la mejor opción, yo por mi parte ya tengo con quien abrir una plantación de tomates :P


PD: debo dar las gracias al compañero Ipas por los links y a Santi por inspiarar este post.

lunes, 29 de septiembre de 2008

Problema (y solución) al instalar .NET Framework 3.5 (IV)

Para continuar con la serie de problemas que nos están dando las instalaciones del .NET Framework 3.5, aquí tenéis otro error al instalarlo:

[XX/XX/XX,XX:XX:XX] RGB Rast: [2] Error: Installation failed for component RGB Rast. MSI returned error code 1601
[XX/XX/XX,XX:XX:XX] WapUI: [2] DepCheck indicates RGB Rast is not installed.

En el directorio temporal del usuario (%TEMP% en Inicio -> Ejecutar) encuentro varios ficheros con el nombre dd_RGB9RAST_x86.msiXXXX.txt (el final del nombre del fichero varía con un número aleatorio) en el que hay más información sobre el error:

=== Verbose logging started: XX/XX/XXXX XX:XX:XX Build type: SHIP UNICODE 3.01.4000.2435 Calling process: X:\XXXXXXXXXXXXXX\setup.exe ===
MSI (c) (2C:48) [XX:XX:XX:XXX]: Resetting cached policy values
MSI (c) (2C:48) [XX:XX:XX:XXX]: Machine policy value 'Debug' is 0
MSI (c) (2C:48) [XX:XX:XX:XXX]: ******* RunEngine:
******* Product: X:\XXXXXX\RGB9RAST_x86.msi
******* Action:
******* CommandLine: **********
MSI (c) (2C:48) [XX:XX:XX:XXX]: Client-side and UI is none or basic: Running entire install on the server.
MSI (c) (2C:48) [XX:XX:XX:XXX]: Grabbed execution mutex.
MSI (c) (2C:48) [XX:XX:XX:XXX]: No se puede conectar al servidor. Error: 0x80070005
MSI (c) (2C:48) [XX:XX:XX:XXX]: Failed to connect to server.
MSI (c) (2C:48) [XX:XX:XX:XXX]: MainEngineThread is returning 1601
=== Verbose logging stopped: XX/XX/XXXX XX:XX:XX ===

Intentamos instalar manualmente el componente RGB RAST (desde aquí podéis descargar la versión de 32 bits y la de 64 bits) pero se produce un error de Windows Installer. Comprobamos que el servicio de Windows Installer está detenido, y no permite arrancarlo dando el siguiente error:

No se puede encontrar la clave de búsqueda solicitada en ningún servicio de activación activa.

Encontramos una solución en esta página que consiste en re-registrar el servicio Windows Installer ejecutando los comandos:
- msiexec /unreg
- msiexec /regserver

Tras esto ejecutamos el instalador del componente y después el instalador del .NET Framework normalmente.

Relacionado:
Problema (y solución) al instalar .NET Framework 3.5 (I)
Problema (y solución) al instalar .NET Framework 3.5 (II)
Problema (y solución) al instalar .NET Framework 3.5 (III)

Problema (y solución) al instalar .NET Framework 3.5 (III)

Como no hay dos sin tres, os presento otro problema que nos ocurrió al instalar el .NET Framework 3.5:


[XX/XX/XX,XX:XX:XX] WIC Installer: [2] Setup Failed on component WIC Installer
[XX/XX/XX,XX:XX:XX] WapUI: [2] DepCheck indicates WIC Installer is not installed.
[XX/XX/XX,XX:XX:XX] WIC Installer: [2] Error code 1603 for this component means "Error grave durante la instalación."

Al revisar el fichero dd_WIC.txt, que está en el directorio temporal del usuario (%temp% desde Inicio -> Ejecutar), encontramos lo siguiente:

4.062: Unable to get File Version
4.062: Failed to copy spupdsvc.exe to system32
4.234: DeRegistering the Uninstall Program -> WIC, 0
4.234: WIC Setup canceled.
4.234: Update.exe extended error code = 0xf00d
4.234: Update.exe return code was masked to 0x643 for MSI custom action compliance.


La solución la encontré aquí y consiste simplemente en renombrar el fichero spupdsvc.exe (que está en el directorio System32 de la instalación de Windows) y volver a ejecutar el instalador.


Relacionado:


Problema (y solución) al instalar .NET Framework 3.5 (II)

Seguimos con los problemas que nos vamos encontrando al instalar el .NET Framework 3.5, hay que tener en cuenta que las instalaciones se realizan en una gran cantidad de equipos (más de 2.000) con diferentes versiones de Windows y con distintas políticas de administración. Si bien es cierto que la gran mayoría no dan problemas, hay algunos en los que los errores de instalación son bastantes rebuscados, como este caso:


[XX/XX/XX,XX:XX:XX] Microsoft .NET Framework 2.0a: [2] Error: Installation failed for component Microsoft .NET Framework 2.0a. MSI returned error code 1603
[XX/XX/XX,XX:XX:XX] WapUI: [2] DepCheck indicates Microsoft .NET Framework 2.0a is not installed.


Esto se debía a que los equipos tenían instalados la versión .NET Framewok 2.0 with Security Updates, que según la knowledge base de Microsoft, da problemas cuando quieres instalar cualquier otra versión del .NET Framework (http://support.microsoft.com/kb/923100/)


El problema añadido es que no permite desinstalar esta versión desde Agregar/Quitar Programas, por lo que es necesario usar una herramienta que haga una desinstalación segura (limpiando el registro y eliminando los ficheros necesarios). Para este caso encontré la .NET Framework CleanUp Utility, creada por Aaron Stebner, que se puede descargar desde este link)

Es muy sencilla de utilizar así que no me voy a detener en explicarlo, lo único que diré es que funciona muy bien y no necesita instalar nada en el equipo en que queremos ejecutarla.


Una vez desinstalado el .NET Framework 2.0 pudimos continuar con la instalación del .NET Framework 3.5 sin problemas.

Relacionado:

Problema (y solución) al instalar .NET Framework 3.5 (I)

miércoles, 3 de septiembre de 2008

Poison Messages en SQL Server Service Broker, ¿qué son y cómo evitarlos?

En varios proyectos en los que estoy trabajando estamos utilizando una característica que se introdujo en SQL Server 2005, Service Broker, SSB para los amigos. Brevemente diré que SSB proporciona una plataforma de comunicaciones basada en mensajes que forma parte del motor de base de datos, si queréis saber algo más tenéis información detallada aquí y aquí.


El caso es que cuando empezamos a hacer pruebas de nuestra aplicación nos encontramos que a veces se detenía el servicio sin motivo aparente, y buscando información nos encontramos con los poison messages.


¿Qué es un poison message?
Un poison message (traducido literalmente “mensaje envenenado”) es un mensaje en una cola que ha excedido el número máximo de intentos de ser recibido por una aplicación. Esta situación puede producirse, por ejemplo, cuando una aplicación lee un mensaje de una cola como parte de una transacción, pero debido a errores (error de conversión, duplicidad de clave,...) no puede procesarlo. Si la aplicación aborta la transacción en la que se recibió el mensaje, éste es automáticamente devuelto a la cola. Si el problema con el mensaje no es solucionado puede provocarse un bucle infinito, provocando un poison message.


Service Broker provee detección automática de poison messages que deshabilita la cola (y te aseguro que no hace ninguna gracia que te pase esto en producción) si una transacción que recibe mensajes de una cola hace rollback 5 veces. Si se llega a dar este caso, el mensaje debe ser eliminado por una aplicación diferente o por un administrador de forma manual.


La detección automática también genera un evento de tipo Broker: Queue Disabled, que puede ser interceptado por un procedimiento almacenado que reactive la cola (vuelva a establecer su STATUS a ON). Además se pueden usar las alertas de SQL Agent para notificar al administrador que la cola se ha desactivado para que actúe en consecuencia.


¿Cómo tratar los poison message?
Debido a que la detección automática de poison messages provoca la detención de la cola, y por tanto, de todos los procesos asociados a ella, las aplicaciones deberían, como parte de su lógica, detectar y sacar de las colas de forma segura los mensajes que sean susceptibles de convertirse en poison messages.


- Usar bloques TRY ... CATCH para capturar todos los errores. Comprobar si la transacción (en caso de que exista) se pueda confirmar con la función XACT_STATE().

- Cuando se detecte un error que potencialmente pueda provocar un poison message, asegurarnos de que el mensaje ha sido sacado de la cola y finalizar la conversación con END CONVERSATION ... WITH ERROR.

- También es muy recomendable guardar el mensaje que provocó el poison message para su posterior tratamiento (podemos corregirlo y volver a introducirlo en el ciclo normal) y guardarnos un log.


Un control de poison messages podría ser algo así:


BEGIN TRY
BEGIN TRANSACTION
RECEIVE
.
.
.
COMMIT TRANSACTION
END TRY

BEGIN CATCH
DECLARE @state INT;
SET @state = XACT_STATE();
SELECT @error = ERROR_NUMBER(), @error_message = ERROR_MESSAGE();

IF @state = 1 -- Hay transacción de usuario activa y se puede confirmar
BEGIN
-- Se finaliza la conversación con error
END CONVERSATION @conversation_handle
WITH ERROR = @error description = @error_message;
COMMIT;
END
ELSE IF @state = -1
-- Hay transacción de usuario activa y no se puede confirmar, sólo revertir
BEGIN
ROLLBACK TRANSACTION; -- Se revierte la transacción

-- Se saca de la cola el mensaje y se finaliza la conversación con error
BEGIN TRANSACTION;
RECEIVE TOP(1) @msgBody = message_body
FROM [queue]
WHERE conversation_handle = @conversation_handle;
END CONVERSATION @conversation_handle
WITH ERROR = @error description = @error_message;
COMMIT;
END
END CATCH




He de reconocer que no es una solución perfecta pero por ahora es lo mejor que he encontrado y funciona bastante bien. En todo caso os recomiendo el blog de Remus Rusanu para profundizar en el uso de Service Broker.



Bola extra

Por si a alguien le interesa, buscando información sobre los poison messages en Service Broker me encontré que MSMQ realiza un tratamiento parecido, tenéis más información en esta página.


Edito: (08/09/08) hasta hoy no me di cuenta que lo de Bola Extra es una copia descarada, digo ... homenaje a los camaradas de Halon disparado, si es que de lo que se come se cría :p


martes, 26 de agosto de 2008

Problema (y solución) al instalar .NET Framework 3.5

Es lo que tiene estar siempre con lo último, que eres de los primeros en encontrar cosas raras :P El asunto es que habíamos preparado un instalador para el .NET Framework 3.5 (ahora lo estamos modificando para el SP1) y empezamos a hacer pruebas en diferentes sistemas operativos:


  • con XP SP2 -> todo bien

  • con XP SP3 -> todo bien

  • con Vista SP1 -> todo bien

  • con Windows 2003 Server SP1 -> todo bien



Todo iba sobre raíles y era demasiado bonito (la ley de Murphy acechaba y no tardó en aparecer) así que probamos con un Small Bussines Server 2003 SP1 y nos saltó un bonito error:

Microsoft .NET Framework 3.5 ha tenido problemas durante la instalación.
El programa de instalación no ser completó correctamente.


Vaya, no me dice nada que me sirva, menos mal que en el registro de errores encontramos lo siguiente:

[XX/XX/XX,XX:XX:XX] XPSEPSC Installer: [2] Setup Failed on component XPSEPSC Installer
[XX/XX/XX,XX:XX:XX] WapUI: [2] DepCheck indicates XPSEPSC Installer is not installed.
[XX/XX/XX,XX:XX:XX] XPSEPSC Installer: [2] Error code 1603 for this component means "Error grave durante la instalación."


Parece ser que no pudo instalar un componente que necesita el .NET Framework, veamos de qué se trata:

The XPSDrv Redist Package (XPSEPSC) contains the system and driver components that enable the XPSDrv print drivers to be installed and to enable the XPSDrv filter pipeline component to function.

¿Son componentes de la cola de impresión? Pues eso parece, no podemos instalar el .NET Framework porque no podemos instalar este paquete. Bueno, vamos a buscar una solución, ya que teníamos el instalador de únicamente este paquete (XPSEPSC-x86-en-US.exe o XPSEPSC-amd64-en-US.exe) lo ejecutamos para ver cuál era el auténtico problema, obteniendo el siguiente error:

Setup could not verify the integrity of the file Update.inf. Make sure the Cryptographic service is running in this computer.

Como os podréis imaginar lo primero que hicimos fue comprobar si el servicio de criptografía (Servicio de cifrado en el manager de Servicios) estaba activado y sí, lo estaba.
En el readme del instalador del .NET Framework 3.5 estaba especificado el error y planteaba una posible solución:

2.1.12. Installation fails if the Print Spooler Service is not running
The installation of the XPSEPSC component requires that the Print Spooler Service be running in the ‘Started’ state. If the Print Spooler Service is not running, the XPSEPSC installer will fail.

To resolve this issue:

Start the Print Spooler service before you install .NET Framework. To do this:
1. Click Start, point to Settings, click Control Panel, and then double-click Administrative Tools.
2. Double-click Services, click to select Services (Local), right-click Print Spooler, and then click Properties.
3. Click Start, and then click OK.

Pero no funcionó, así que buscamos el error en el Technet y encontramos lo siguiente: You cannot install some updates or programs. Os recomiendo que ni intentéis leerlo en el “castellano” del traductor automático porque no os enteraréis de nada.

En este documento se presentan 11 posibles soluciones, algunas más fáciles que otras, y para resumir diré que la que funcionó en nuestro caso fue la siguiente:

Method 4: Reregister DLL files that are associated with Cryptographic Services
To register .dll files that are associated with Cryptographic Services, follow these steps:


1. Click Start, click Run, type cmd in the Open box, and then OK.Note On a Windows Vista-based computer, click Start, type cmd in the Start Search box, right-click cmd.exe, and then click Run as administrator.

2. At the command prompt, type the following commands, and press ENTER after each command:
regsvr32 /u softpub.dll

regsvr32 /u wintrust.dll
regsvr32 /u initpki.dll
regsvr32 /u dssenh.dll
regsvr32 /u rsaenh.dll
regsvr32 /u gpkcsp.dll
regsvr32 /u sccbase.dll
regsvr32 /u slbcsp.dll
regsvr32 /u mssip32.dll
regsvr32 /u cryptdlg.dll
exit

Note Click OK if you are prompted.Note Microsoft Windows 2000 does not include the Sccbase.dll file. If you are running a version of Windows 2000, omit the Sccbase.dll file.

3. Restart your computer.

4. Click Start, click Run, type cmd in the Open box, and then click OK.

5. At the command prompt, type the following commands, and press ENTER after each command:
regsvr32 softpub.dll

regsvr32 wintrust.dll
regsvr32 initpki.dll
regsvr32 dssenh.dll
regsvr32 rsaenh.dll
regsvr32 gpkcsp.dll
regsvr32 sccbase.dll
regsvr32 slbcsp.dll
regsvr32 mssip32.dll
regsvr32 cryptdlg.dll
exit

Note Click OK if you are prompted.Note Microsoft Windows 2000 does not include the Sccbase.dll file. If you are running a version of Windows 2000, omit the Sccbase.dll file.

6. Restart the computer.

He de reconocer que nos funcionó sin necesidad de reiniciar la máquina, después de volver a registrar las DLLs volvimos a ejecutar el instalador y fue todo como la seda :D

PD: en caso de que falle la instalación y no tengáis información de qué ha pasado podéis consultar los ficheros de log que crea el instalador:

- dd_dotnetfx35install.txt
- dd_dotnetfx35error.txt
- dd_depcheck_NETFX_EXP_35.txt

que dependiendo de si se finaliza o no la instalación estarán en un directorio temporal o uno definitivo en la carpeta WINDOWS, os recomiendo que los busquéis porque están bastante “escondidos”.

miércoles, 6 de agosto de 2008

Libro: Microsoft SQL Server Compact 2008 SP1 Referencia Completa




Es un auténtico placer para mi poder recomendaros el libro de un compañero y amigo, Jose Miguel Torres (Device Aplication Development MVP) acaba de publicar con Krasis Press Microsoft SQL Server Compact 2008 SP1: Referencia Completa.

Tuve el honor de ser uno de los primeros lectores de esta obra y os la recomiendo a todos los que estéis buscando iniciaros o profundizar en todo lo referente a esta especificación de SQL Server.

Gran trabajo Jose, ENHORABUENA!!!

miércoles, 11 de junio de 2008

DataBindings automágicos (II): una solución quiero!!!!

Bueno, seguimos con el tema, después de la presentación del problema voy a intentar ofrecer una solución aceptable y rápida.

Está claro que el método que guarda los registros no hace lo que nos gustaría que hiciese, así que vamos a cambiarlo un poco. Nos vamos al método pedidoBindingNavigatorSaveItem_Click y añadimos el siguente código:

private void pedidoBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{

this.Validate();

this.pedidoBindingSource.EndEdit();

this.pedidoTableAdapter.Update(this.dataSet1.Pedido);

// Después de hacer el Update, llamamos al método Fill para que
// recargue los registros de la tabla de Pedido


this.pedidoTableAdapter.Fill(this.dataSet1.Pedido);


// Obtenemos el identificador del último registro que haya en el Pedido del Dataset
// que se debería corresponder con el que acabamos de insertar


int id;
id = (int)this.dataSet1.Pedido.Rows[this.dataSet1.Pedido.Rows.Count - 1]["id"];


// Ahora vamos a las líneas de detalle y le cambiamos el idPedido sólo a las
// que acabamos de añadir


foreach (System.Data.DataRow row in this.dataSet1.Detalle_Pedido.Rows)
{

if (row.RowState == DataRowState.Added)
row["idPedido"] = id;

}


this.detalle_PedidoBindingSource.EndEdit();


// Forzamos el Update

this.detalle_PedidoTableAdapter.Update(this.dataSet1.Detalle_Pedido);


// y nos volvemos a traer los registros de Detalle_Pedido, con lo que tendremos
// los identificadores actualizados


this.detalle_PedidoTableAdapter.Fill(this.dataSet1.Detalle_Pedido);


// Nos movemos al último registro de la cabecera
// que debería ser el que acabamos de añadir


this.pedidoBindingSource.MoveLast();

this.Refresh();

}


¿Qué problemas plantea esta solución?

Para empezar, es una solución para salir del paso (una ñapa como una casa :P), y está claro que no se puede tomar como definitiva. En entornos en los que la concurrencia sea un problema hay que usar técnicas de concurrencia y bloqueos sin remisión con lo que en vez de un problema pasamos a tener 2, la concurrencia y los interbloqueos (deadlocks y similares).

Segundo, el principal problema es que estamos suponiendo que el último registro es efectivamente el nuestro, pero eso puede ser cierto o no. Tendríamos que tener la certeza absoluta de que es así, lo que implicaría hacer consultas sobre la base de datos o bloquear registros.

Y para acabar, el último que guarda en este escenario de concurrencia tiene constancia de todos los registros en cuanto guarda, pero el primero que guarde no obtiene todos los registros hasta que introduzca uno nuevo. Esto puede ser problemático o no, dependerá de nuestro escenario particular.


Conclusiones

- Las cosas fáciles no suelen tener en cuenta los problemas complejos, que suelen ser con los que nos tenemos que pelear en la vida real. Hacer databinding con drag-and-drop están muy bien para hacer pequeños proyectos, pero cuando entra en juego la concurrencia tenemos que saber qué es lo que hay por debajo, y eso sólo se consigue si tenemos muy claro cómo trabaja ADO.NET y sus clases.

- No te preocupes, que lo que te está pasando seguro que le pasó a un millón de programadores antes y casi todos encontraron una solución. Sólo te queda encontrar la tuya, que dependerá de tu problema concreto mucho más de lo que te imaginas.

- Vamos, que no hay una solución definitiva para el tema del acceso a datos y mucho menos el de la concurrencia. Yo personalmente recomiendo usar un ORM para que mapee el modelo de base de datos en clases, que los hay muchos y muy buenos por ahí.

Eso sí, a la espera que el Entity Framework sea lo que todos esperamos que sea ;)

martes, 20 de mayo de 2008

He leído: Agile Project Management with Scrum







Título: Agile Project Management with Scrum
Autor: Ken Schwaber
Editorial: Microsoft Press
ISBN-10: 073561993X
ISBN-13: 978-0735619937
Páginas: 192

En Amazon



Me gustó:
Antes de nada recordar que Ken Schwaber, junto con Jeff Sutherland, es uno de los creadores de SCRUM, por lo que leer un libro suyo es como si Pitágoras te enseñase matemáticas o Kant filosofía.

El libro está planteado mediante una serie de (supuestos) casos prácticos que le sucedieron a Ken durante su trabajo como Scrum Master en varios proyectos. En estos casos se plantean (de forma muy acertada) situaciones tanto de conceptos de SCRUM como de soluciones para el día a día.

Ya sólo con echarle un vistazo al índice nos damos cuenta que se tratarán todos los aspectos relevantes sobre SCRUM: el Scrum Master, el Producto Owner, el equipo, los informes, ... Pero lo interesante es cómo se tratan, porque la base teórica del SCRUM se deja para el primer capítulo y los 3 apéndices finales, mientras que el resto de capítulos son casos sumamente prácticos, en los que se plantea una problemática (que podría suceder en cualquier empresa que esté implantando SCRUM) y se muestra una posible solución. Además, cada capítulo acaba con una reflexión del autor, un “Lecciones aprendidas” que resulta muy didáctico.

El libro es muy fácil de leer, aunque está en inglés no abusa del vocabulario técnico, y es muy ameno porque los casos que se plantean se van encadenando a lo largo de los capítulos pero con cierta independencia, lo que no te obliga a recordar qué había pasado en un momento anterior.

No me gustó:
Algunos casos de los que se plantean en el libro son un poco “increíbles”, digamos que se solucionan de una manera demasiado sencilla y sin que implique las duras batallas que todos hemos librados con nuestros jefes, compañeros o clientes.

En mi opinión se da una visión demasiado subjetiva sobre SCRUM, resaltando todas sus bondades y presentándolo como la solución definitiva para la gestión de proyectos. Pero bueno, no me esperaba otra cosa.

Le falta:
Para mi nada, es un libro bastante redondo.

Lo recomiendo para:
Todo aquel que esté planteándose iniciarse en SCRUM, puesto que es una auténtico lujo que uno de sus creadores te lo explique paso a paso.

lunes, 19 de mayo de 2008

DataBindings automágicos (I)

(No, no me he equivocado quería escribir autoMÁGICOS no automáticos :P el porqué ya ser verá en el post)

Hace un par de semanas me mandó un mail un lector del blog (Germán) comentándome una duda con el uso de Datasets tipados como origen de datos en Windows Forms.


Dado que ya me había pasado algo similar en algún proyecto en el que trabajé pero del que no recuerdo cómo lo solucionamos, decidí ponerme manos a la obra para hacer un proyecto que tenga la problemática que me planteó Germán y tratar de encontrar una solución óptima. Y como le comenté a Germán, lo pongo aquí para que le sirva a más gente ;) Vamos a empezar:

Tenemos una base de datos a la que llamaré PRUEBAS, con únicamente 2 tablas: Pedido y DetallePedido, con el siguiente esquema:

Pedido
id -Identity PRIMARY_KEY
Descripcion -Varchar(10)

DetallePedido
idDetalle - Identity PRIMARY_KEY
idPedido - Int
Cantidad - Int
Precio - Float

Típicas tablas maestro-detalle, relacionadas por Pedido.id – DetallePedido.idPedido


Creamos un proyecto Windows Form en Visual Studio 2005, y añadimos un Dataset donde agregamos las 2 tablas, que nos quedará de la siguiente forma:





Ahora nos vamos al formulario, y desde el explorador de Origenes de Datos, arrastramos los campos de la tabla Pedidos y los relacionados de DetallesPedido (Atención: tiene que ser el que cuelga de Pedido para que nos mantenga la relación)





Con lo que el formulario nos quedará más o menos así:


Ahora nos vamos a código y buscamos el evento pedidoBindingNavigatorSaveItem_Click que es el que se produce cuando presionamos el botón de Guardar Cambios, y añadimos las 2 líneas en rojo para que guarde también las líneas de detalle:

private void pedidoBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.pedidoBindingSource.EndEdit();
this.pedidoTableAdapter.Update(this.dataSet1.Pedido);
this.detalle_PedidoBindingSource.EndEdit();
this.detalle_PedidoTableAdapter.Update(this.dataSet1.Detalle_Pedido);
}

Si lo probamos debería funcionar perfectamente, permitiendo movernos entre registros, agregar nuevos pedidos y sus líneas de detalle correspondientes. Ahora viene el problema que nos plantea Germán, ¿y si hay 2 usuarios añadiendo pedidos a la vez?

Pues vamos a probarlo, compilamos, arrancamos 2 veces el ejecutable y creamos un nuevo pedido en cada instancia. ¿Qué sucede? Como es normal asigna un valor al campo id del pedido, que obtiene de sumarle 1 al último valor más grande que exista en la tabla ese momento (ojo: no es el valor que le corresponda al IDENTITY) con lo que nos dará el mismo valor para las 2 instancias.




No vamos a hacer nada más por ahora, guardamos y vemos que pasa.



Como es normal nos ha actualizado el id del pedido con el valor que le ha asignado en la tabla de la base de datos. Bien, es el comportamiento normal y esperado.

Vale, ahora vamos a introducir líneas en estos 2 pedidos que acabamos de guardar:



Como en el caso de las cabeceras de pedido, nos asigna un valor al campo idDetalle, que vuelve a ser el valor máximo del campo en la tabla sumándole 1, con lo que vuelve a ser el mismo valor para las 2 instancias. Guardamos y nos asigna el valor que le corresponde en la tabla.



Vale, todo va bien, hemos añadido una cabecera y una línea y no hay ningún problema, ¿seguro que no hay problemas?

Vamos a hacer lo mismo que antes pero cambiando un poco la forma de hacerlo, ahora vamos a guardar después de añadir la línea de detalle, a ver qué pasa.

Vaya sorpresa, nos ha desaparecido la línea del 2º pedido que guardemos, ahora si nos movemos por los registros esa línea no aparece en ninguna de las 2 instancias, pero si nos vamos a la tabla veremos que está con el identificador que le asignó a la primera instancia que se guardó.

Si cerramos los formularios y volvemos a abrirlos nos encontraremos un pedido con 2 líneas y otro sin líneas. Esto se debe a que al asignar el valor del identificador a las cabeceras también lo hace con las líneas, pero al guardar no actualiza el identificador del pedido en las líneas, con lo que se queda el que tenía en un principio ... ups, vaya lío que hemos montado, ¿no?

Bueno, creo que ya se puede ver por donde van los tiros: ¿nos fiamos o no nos fiamos del código generado automáticamente al arrastar elementos desde los orígenes de datos?

Como este post ya es bastante largo, os presentaré más cosas sobre DataBinding, más problemas y cómo solucionarlos en un próximo post, permanecer atentos al blog :)

miércoles, 20 de febrero de 2008

He leído: Microsoft Windows Workflow Foundation Step by Step de Ken Scribner



Título: Microsoft® Windows® Workflow Foundation Step by Step
Autor: Ken Scribner
Editorial: Microsoft Press

ISBN-13: 978-0-7356-2335-4
ISBN-10: 0-7356-2335-X

En Amazon

Páginas: 512



Me gustó:


Como el propio nombre indica el libro explica Windows Workflow Foundation (WF) paso a paso, con muchos ejemplos, muy bien explicados y con capturas de todos los pasos que se realizan. Es muy recomendable tanto para los que no han visto nunca WF como para los que ya tienen cierta experiencia porque trata casi todos los aspectos técnicos de esta tecnología, pero desde los ejemplos, lo que lo hace muy fácil de leer y muy ameno.

El libro está muy bien distribuido, y los capítulos bien estructurados, incluyendo en cada uno descripciones detalladas de las clases que se utilizan, indicando sus propiedades y métodos. Lo que hace que sea una buena referencia una vez leído.

Además, tiene una cosa que me gustó mucho: al principio de cada capítulo explica qué temas se tratarán y al final hay una referencia rápida con los conceptos clave. Muy buena idea.

También incluye un CD con los ejemplos y el propio libro en formato PDF.


No me gustó:

Por ponerle alguna pega, hay momentos en que los ejemplos se alargan demasiado, 10 páginas para explicar un workflow sin mucha complejidad resultan excesivas a veces.


Qué le falta:

En mi opinión le faltaría un capítulo o 2 sobre la implementación de WF con Windows Communication Foundation (WCF) ya que son tecnologías que se complementan muy bien. Se trata el tema de Web Services, pero para mi gusto queda un poco obsoleto.

Además, estaría bien que se profundizara un poco más en el tema de las transacciones, lo veo un poco flojo para un libro tan completo.

En una posible segunda edición estaría bien que entrasen las novedades que trae el Framework 3.5 en lo que respecta a WF.

jueves, 31 de enero de 2008

He vuelto, bueno, mejor dicho, ... En breve volveré ;)

Hacía tiempo que no escribía ningún post por falta de tiempo. Las prácticas de la universidad, los exámenes, las Navidades y una baja inoportuna por una fractura son los culpables de esto.

Y ahora que me planteo volver al mundo blogosférico lo primero que viene a mi mente es:

¿Por qué lo hago?
¿Por qué dedico minutos, horas o incluso días en probar un código que puede que no llegue a usar en ninguna aplicación?
¿Por la fama y el dinero? Pues va a ser que no, porque aún no he recibido ningún reconocimiento y menos aún un triste céntimo de euro.
¿Por tener un sitio donde desahogarme? Por ahora no lo necesito, si me preocupa algo cojo la moto y me voy a dar una vuelta, es el mejor remedio que he encontrado y me funciona muy bien.
¿Por hacer amigos o pretender que me conozcan? Ummm, va a ser que no.
¿Para poder fardar de tener un blog? Casi nadie de los que me conocen han entrado en mi blog. Y los que lo hacen son compañeros de trabajo con mucho más de enseñarme que lo que les pueda enseñar yo a ellos.
¿Para que me sirva en las entrevistas de trabajo? Seguro que no, no lo tengo ni en el currículum ni lo digo en las entrevistas.

No, no es nada de esto, me parece que es algo más profundo y raro. Es algo que creo que sólo se produce en el mundo de la informática en general y la programación en particular: es para ayudar. Sin más, no hace falta nada a cambio.

Creo que en mi caso todo empezó en los foros de la gran comunidad que es PortalFox donde empecé a aportar mi pequeño granito de arena. Lo cierto es que fueron unas pocas respuestas a preguntas fáciles pero comunes en el mundo del zorro. Y lo hacía más por la satisfacción de ayudar que por el hecho de que me lo agradecieran. Además, era la única forma que me parecía que podría devolver lo que la comunidad me había dado: conocimiento.

Yo soy de los que ante un problema primero busco todas las soluciones que se me pasan por la cabeza, sean más o menos lógicas, y después de probarlo todo pido ayuda. Algunos dirán que se pierde mucho tiempo así, pero yo creo que es la mejor forma de aprender. Y lo cierto es que es un verdadero placer recibir ayuda cuando no se te ocurre nada más, cuando ya has probado todo y no sabes cómo seguir.

Es una gran suerte poder contar con otra gente que desinteresadamente te presta su tiempo y esfuerzo sin pedir nada a cambio, que forman comunidades para ayudar, que se implican tanto en los problemas de otros como en los suyos propios, que escriben libros para compartir y que tienen ganas de enseñar, de dar conferencias sobre las cosas que dominan (sin leer el discurso preparado por el fabricante), de hablar durante horas sobre lo que les apasiona, de estar siempre dispuestos para echar una mano, ...

Así que este post que empezaba mirándome el ombligo acaba con un gran GRACIAS!! a todos los que os dedicáis a esto y os lo curráis tanto para que nos sea más fácil a los demás.

Sin más, y volviendo al tema, pronto tendré preparado un post sobre WCF, o sobre WF, o sobre Service Broker, o sobre lo primero que se me ocurra, en VB.NET, o en C# lo que sea, pero espero que le sirva a alguien de ayuda y no se quede sólo en un poco de información perdida en la Red de Redes.


PD: en el mundo motero también pasa algo parecido, pero sale más del corazón que de la cabeza ;)