Jorge Serrano - MVP Visual Developer - Visual Basic

Introducción

Lo que a continuación voy a tratar es un tema de reflexión general acerca de nuestra profesión y las aspiraciones de los individuos respecto a la carrera profesional.


Como está montada la carrera profesional informática hoy día

La carrera profesional de informática está montada hoy día de manera tal que un desarrollador Software que quiera cobrar más, debe progresar en el escalafón de perfiles hasta convertirse en... ¿jefe de proyecto por ejemplo?.

Sin duda, esto me recuerda a los rangos militares, donde cuanto más asciendas, más mandas, pero también más cobras,... y no nos olvidemos, la motivación mayoritaria es el sueldo por mucho que nos quieran vender muchas veces que son otras cosas.


Las aspiraciones personales

Hablar por lo tanto de aspiraciones de las personas es casi poner una línea de texto por cada individuo, pero tratando de ser generalista, me atrevo a afirmar que hay dos tipos de individuos cuyo objetivos son:

  • Progresar en su carrera profesional para aprender, haciendo lo que realmente le gusta, y en mi caso, aprovechándose de que su profesión es además su propio hobby.
  • Sacrificar aquello que le gusta por intentar ganar más dinero, y muchas veces, ganar más dinero implica tener un mejor puesto dentro de la organización y por lo tanto, mayor responsabilidad dentro de ella.

Y aquí entra en juego el motivo real de mi entrada.
¿Debe ganar más el que más alto se encuentra dentro de la jerarquía o el que lo hace mejor en su ámbito?.


¿Y si gana más el que lo demuestre con independencia de su rol?

No voy a entrar en la defensa del que piensa que subir en el escalafón u organigrama de la empresa se merece más dinero que otros debido a que su responsabilidad es mayor, etc etc... pero sí voy a entrar en otro terreno que es antagónico a ese y que incluso lo podría hacer tambalear y caer.

Imaginemos un desarrollador de Software.
Imaginemos a ese mismo desarrollador con un nivel impresionantemente destacable, de esos desarrolladores productivos y que hacen ganar dinero a la empresa.
Imaginemos a ese mismo desarrollador que le gusta lo que hace, que cada día que se levanta por las mañanas se levanta con ilusión y canturreando porque no va a trabajar, va a divertirse, porque en definitiva, tiene pasión por lo que hace y cómo lo hace.

Imaginemos ahora que viene su jefe y le dice un día que es excelente en su trabajo y que si quiere ganar más dinero.
¿Cuál creéis que será su respuesta?.
Vamos... que no es imbécil... le dirá... ¡por supuesto!.

Imaginaros entonces ahora que su jefe le dice que debe dejar de ser programador y... ¿subir su escalafón a analista programador?.
Yo me pongo en la piel de ese programador y de verdad, creo que es probable que acceda, pero supongamos que lo tiene tan claro que sólo quiere hacer lo que sabe hacer mejor que prácticamente nadie… ¡programar!. Lo más seguro es que ante tal tesitura entre en barrena esa misma tarde.
¿Tiene sentido forzar a alguien realmente destacable en su trabajo a cambiar su rol sólo para ganar más dinero?.

Si este individuo del que hablamos es realmente productivo para la empresa, y la empresa está contenta con él,... ¿no parece más lógico y sensato que siga realizando su trabajo como hasta ahora pero que gane más dinero del que gana si realmente se lo merece?. ¿Es necesario que gane más dinero cambiando su rol?.

Supongamos en este punto que siendo programador ganara más dinero que algunos de los analistas programadores de la empresa. ¿Os parecería justo?.

¿Y que pasa si en lugar de un programador son dos los que se merecieran tener un mayor sueldo que un determinado analista programador de la compañía?. ¿Sería doblemente injusto?.

No sé en otros países, pero en España la situación es esta.
Para ganar más dinero tienes que progresar dentro del organigrama, y nadie por encima de tu perfil puede cobrar menos que tú. No es una ley escrita en muchos casos, pero sí comprendida así por la inmensa mayoría de nosotros.

Es decir, podemos caer en el grave error de hacer que la persona que estaba trabajando híper motivada, de forma resolutiva, implicada y haciéndole ganar dinero a la empresa, termine cambiando de empresa o buscándose otra forma de vida.

Creo firmemente que los sueldos no pueden ir atados y de la mano únicamente a la jerarquía organizativa, también conviene tener en cuenta lo que la empresa quiere. ¿Tener a los mejores y cotizados dentro de su organización, o crear una jerarquía organizativa de competición interna donde la lucha sea de clases y no por méritos y conocimientos?.

Pienso que lo más inteligente para una empresa es lograr crear un lugar de trabajo dónde compartir y crecer, favorezca al individuo y al final, a la empresa y empleados que forman parte de esa colectividad. Sin embargo, hay muchos aspectos culturales que impiden actuar con lógica.

Sólo las empresas valientes harán y lograrán grandes metas, aquellas que se atrevan a romper determinadas normas no escritas. Las demás, seguirán siendo un número más, y los mejores estarán moviéndose de una empresa a otra hasta que encuentre una que realmente le valore por lo que hace, no por lo que ponga en su tarjeta de visita.

Publicado por Jorge Serrano | 9 comment(s)
Archivado en:

Introducción

En el pasado TechEd que se celebró en Europa (en Madrid en esta ocasión), tuve la oportunidad de hablar con algunas de las personas que fueron allí.

Aunque y como es lógico, hablamos de muchas cosas diferentes (situación económica actual y como afecta esto en el sector, etc), fue casi obligado hablar de las tecnologías Microsoft que estaban cambiando, las que se estaban descartando y las que irrumpían con fuerza.

Y como suele ser habitual, una cosa lleva a la otra, y lo que se empieza de una forma termina dándose la vuelta una y otra vez y terminamos hablando de siglas, tecnologías emergentes de todo tipo y naturaleza, frameworks de toda clase y color, cachivaches varios,... y bueno, nos encontramos sumidos en una gran e interesante conversación donde se entremezclan tantas cosas y tendencias que a veces tienes que para para tomar aire y no agobiarte.

Fue entonces cuando les dije a las personas que estaban conmigo en aquel momento que yo basándome en mi experiencia siempre que hablo de esto, termino hablando del término surfista tecnológico que les expliqué brevemente y que ahora voy a compartir públicamente con todos vosotros y que tan bien viene en estos momentos en los que mucha gente se va a la playa de vacaciones.


La marea tecnológica

Para hablar del surfista tecnológico, es preciso hablar antes de la marea tecnológica.

La tecnología aparece, cambia o muta, se transforma, muere... vamos... como el anuncio, nace, crece, se reproduce y muere. Y dentro de esa marea tecnológica nos encontramos todos los amantes de la tecnología.

Aparece un framework de "nosequé", y sin quererlo tenemos un montón de iniciativas open source y de pago de ese "nosequé". Y la gente empieza a decirte que "a" es mejor que "b", y al cabo de los meses aparece "c" que es mejor que ninguna de las dos, pero resulta que la última actualización de "a" es la leche,... pero "d" ha aparecido y es lo que lleva ahora... y vamos... esto se convierte en un sin vivir.

Sin embargo, los amantes de la tecnología no somos de los que nos quedamos mirando las olas del mar, tenemos que meternos dentro y tratar de saltar algunas y de meternos por debajo en otras,... dicho de otra forma, ¡lo queremos conocer todo!.


El surfista tecnológico

Y aquí entra en juego una nueva pieza... el surfista tecnológico.

Pensemos ahora que todos esos amantes tecnológicos son (somos) surfistas, y que lejos de querernos quedar mirando las olas del mar, nos adentramos dentro del agua para conocerlas bien, para coronarlas y surfearlas, para echarle un pulso a la física y a la habilidad.

Pero dentro del grupo de surfistas tecnológicos, tenemos (de forma muy general), el surfista novel y el surfista experimentado.

El surfista novel es aquel que se sube en todas esas olas tecnológicas, es decir, todas le parecen buenas para coronarlas y surfear encima de ellas.
Su limitada experiencia no le ayuda a tomar decisiones de manera eficiente, y cree que debe conocer absolutamente todo porque piensa que todo lo que aprenda le hará más fuerte.

El surfista experimentado sin embargo, ya fue surfista novel y sabe que debe dosificar su tiempo y que ya sabe por experiencia propia, que no todas las olas son interesantes, muchas de ellas parecían buenas olas para surfear pero solo eso,... lo parecían. Empezaba a crecer como una ola excelente, pero de repente se desvanecía rápidamente.
El surfista experimentado se hace selectivo, deja pasar muchas olas hasta que a lo lejos en el horizonte, otea una que le parece interesante, y que según se acerca a él ya tiene claro si es una ola de las buenas o de las que se desvanecen rápidamente, es decir, una ola a la que le interesa subirse o dejarla pasar para elegir otra que considera mejor.
Lógicamente, experimentado no significa libre de error, y en algunas ocasiones, se sube a la ola incorrecta (el que esté libre de pecado que tire la primera piedra).

Los buenos tecnólogos se hacen a base de experiencia, de ser un surfista novel al principio, y de poco a poco y basándose en su experiencia y errores, lograr ser un surfista experimentado que sabe detectar rápidamente que ola tecnológica le conviene y sobre cual quiere subirse para hacer grandes piruetas (grandes avances en su carrera profesional).

¿Te es reflejado en este símil?. ¿Cuál es tu idea?, ¿crees que debemos conocer todo lo que aparece o debemos ser selectivo como el surfista experimentado?.

Publicado por Jorge Serrano | 2 comment(s)
Archivado en:

Introducción

Muchos piensan que la gamificación o gamification es algo bastante reciente, pero hoy voy a demostrar como esto no es así.

Antes de empezar a fondo con esta entrada me gustaría empezar poniendo en contexto y de forma más directa el significado que se da en la Wikipedia sobre la gamificación o gamification.

En ella se dice: “La gamificación sirve para hacer el ámbito de aplicación más atractivo, y mediante el fomento de los comportamientos deseados, aprovechándose de la predisposición psicológica de los seres humanos para participar en juegos.”.

La conexión psicológica

Como se ve, la gamificación tiene una fuerte vinculación con la psicología del individuo, sin embargo, mucha gente relaciona erróneamente esta “técnica” únicamente con los juegos.

El propósito principal que hay detrás de la gamificación es la de animar e incentivar la participación, con el propósito principal de mejorarse y ganar a los demás, es decir, ser competitivo contra uno mismo y contra otros superando retos y obteniendo logros.

Si eres un jugador por ejemplo de juegos de Xbox, de Windows Phone o de Windows 8, sabrás a qué me estoy refiriendo. Pero no sólo de juegos come el hombre…

¿Dónde se emplea la gamification?

Pese a su nombre “game”, la gamificación no sólo se emplea en el ámbito de los juegos. De hecho, su uso se está extendiendo a otros planos muy diferentes como aplicaciones Software de otra índole a la de los juegos (como por ejemplo DropBox), e incluso actividades lúdicas que nada tienen que ver con el Software.

Muchos lo quieren ver como algo muy moderno, muy cool,… pero no todo el mundo sabe que por ejemplo, las legiones romanas (de las cuales soy un apasionado y cada vez más), ya lo usaban, e incluso si rasco más y más en la historia del ser humano lo encuentre años, siglos o milenios atrás.

Buscando los orígenes de la gamificación

Así que me gustaría que esta entrada rozara la parte tecnológica e hiciera un guiño a la historia tratando de enseñar si es posible, el origen de esta filosofía y demostrar como esto de la gamification que últimamente está bastante de moda no es algo de reciente fabricación.

Para ello, voy a poner encima de la mesa a las legiones romanas como origen de lo que hoy día se conoce como “gamification”. ¿Quieres aprender o saber cómo lo hacían?,… pues continúa leyendo.

Las legiones romanas y la gamificación

Podría estar hablando de las legiones romanas durante un buen rato, pero me ceñiré únicamente al tema de esta entrada, la gamificación.

La sociedad romana ha aportado una riqueza y un legado cultural incalculable. Apartando la parte amarga y negativa de la sociedad romana (que también las hubo), me quedaré sobre esas cosas con la organización militar, la cual en muchas de sus características, se utilizan aún hoy en los ejércitos más modernos e incluso en diferentes profesiones civiles.

Uno de esos ejemplos tiene que ver con las contiendas y luchas guerreras de conquista y defensa.

Pero para lograr que el ejército estuviera motivado y animaran a otros a entrar en esa dinámica de competitividad, reto, logros y motivación, se apoyaba en la gamificación.

De hecho, un legionario podía obtener dinero, o bien obtener dinero y diferentes condecoraciones a lo largo de su carrera militar, y habiendo condecoraciones más ostentosas y otras menos ostentosas, pero todas ellas anheladas por todos y cada uno de los militares romanos, siendo condecorado y agasajado en público y ante los ojos de todos sus compañeros que lejos de sentir envidia, sentían orgullo y deseos de anhelo por esa misma suerte.

El objetivo era doble. Por un lado, premiar a quien había logrado justamente un hito o un reto. Por otro lado, animar a los demás a lograr los mismos objetivos o incluso mayores con quién habían compartido terreno en el campo de batalla.

Adicionalmente, esas condecoraciones o recompensas eran anotadas en el archivo o registro de cada militar romano. ¿Te suena de algo?.

Obviamente, hoy día y hablando en clave “juegos de ordenador”, ese registro se hace en un servidor en la cuenta de cada usuario, y los logros son anotados en esa cuenta que puede ser revisada por otros jugadores para ver quién tiene más logros que otros y en qué juegos.

El objetivo era más o menos el mismo, motivar a la tropa a ser competitiva, avivando las ansias no sólo por la victoria, sino también por lograr ciertos reconocimientos que impulsaran la carrera militar del soldado romano.

Pero para que se vea que no sólo los romanos otorgaban este tipo de premios, pararé un momento en la cultura griega impulsora muy posiblemente de lo que sería el embrión de la gamificación que posteriormente pondrían en práctica de forma extensible los romanos:

Y aquí va una pequeña lista de condecoraciones o logros de las legiones romanas (hay muchas más):

Como podemos apreciar, estos premios o reconocimientos, servían para mantener el ánimo y las ganas dentro de la legión romana, que tantos éxitos obtuvo a lo largo de bastantes siglos.

Para concluir, citaré a Julio César como ejemplo de éxito, quién logró una corona cívica (la condecoración al valor más alta que otorgaba la República Romana) cuando era muy joven, y desfiló gracias a ello en un lugar destacado en los desfiles triunfales en Roma.

Publicado por Jorge Serrano | con no comments
Archivado en: ,

Despedida

La semana pasada después de estar meditándolo mucho durante los últimos meses, tomé una decisión bastante difícil pero que estoy convencido de que será acertada.

Después de bastantes años detrás de MADNUG, tomé la decisión de dejar de coordinar MADNUG junto a otros fieras como Luis Fraile, Bruno Capuano, Javier Holguera, Víctor González y Javier Torrecilla e intentar otro proyecto diferente.

Los motivos para dejar MADNUG son estrictamente personales, sin embargo, considero que MADNUG se queda en buenas manos y en la medida en que me sea posible, seguiré apoyándolo, aunque no como antes ya que es materialmente imposible.

Grupo de Usuarios, Comunidad… ¿renovar o morir?

Una de las preguntas que nos estamos haciendo muchos en estos momentos es si tienen sentido los grupos de usuarios y comunidades.

Hace unos años, este tipo de grupos sí tenían sentido y han ayudado y mucho a todos los entusiastas de las tecnologías, especialmente tecnologías Microsoft, sin embargo creo que han ido perdiendo fuerza con el paso de los años.

Me atrevo a afirmar que en esa tesitura se encuentra actualmente la casi totalidad de grupos de usuarios y comunidades de tecnologías Microsoft.

Cuando preguntas a unas y otras personas que han estado en la cresta de la ola de los grupos de usuarios y comunidades, te das cuenta de que la mayoría pensamos de una forma similar. Dicho de otra forma… los grupos de usuarios y comunidades están muertos.

Con la idea y propósito de cambiar esta dinámica nace MsCoders Madrid, iniciativa en la que me he embarcado junto a mi compañero de trabajo y amigo Luis Ruiz Pavón (un crack).

MsCoders Madrid NO es ni un grupo de usuarios NI una comunidad

MsCoders Madrid no nace con la filosofía de ser un grupo de usuarios ni una comunidad,… es más, no queremos que esas palabras se nombren, así que va a ser la última vez que las escriba cuando hable de MsCoders Madrid, y es que MsCoders Madrid es otra cosa muy diferente, más global aún a lo que esas palabras daban a entender.

MsCoders Madrid nace con el propósito de ser un punto o lugar de encuentro de reuniones técnicas en el que la gente comprenda, aprenda, muestre y enseñe sus conocimientos sobre tecnologías Microsoft, un lugar en el que se debata, se enriquezca, se sugiera y se disfrute.

No creemos en la idea de que durante 2 horas venga alguien a dar una charla a hablar de un tema concreto, cierre su PC y se acabe la charla. Creemos más en la interactuación de todas las personas, en que todos participemos y que todos compartamos, en el debate enriquecedor, en el punto o lugar de encuentro, en el sumar y no restar. No me puedo creer que nadie tenga nunca nada que aportar, eso no es imposible, es simplemente mentira. Todos tenemos mucho que contar además de escuchar. Nadie es ni más grande ni más pequeño que otros. Esta es la filosofía de MsCoders Madrid, la de contar con todos.

No quiero hablar más de MsCoders Madrid, simplemente que vosotros lo descubráis con vuestros propios ojos e invitaros a participar en él.

Se bienvenido a MsCoders Madrid.

Síguenos en Twitter MsCodersMadrid.

Síguenos en Facebook.

Síguenos en Google+.

Síguenos en Eventbrite.

Publicado por Jorge Serrano | 2 comment(s)
Archivado en:

Microsoft ha publicado un nuevo eBook gratuito titulado Prism for the Windows Runtime.

El documento, en inglés, tiene 222 páginas y pertenece a la colección de Patterns & Practices.

Está elaborado por 7 autores y está focalizado en aplicaciones de negocio de Windows Store utilizando C# y XAML.

Dentro del documento encontraremos los enlaces de descarga para las diferentes partes tratadas en el libro.

Los bloques tratados en el libro son los siguientes (hago un copy/paste literal del libro):

  • How to implement pages, controls, touch, navigation, settings, suspend/resume, search, tiles, and tile notifications.
  • How to implement the Model-View-ViewModel (MVVM) pattern.
  • How to validate user input for correctness.
  • How to manage application data.
  • How to test your app and tune its performance.

Los prerrequisitos son Windows 8 y Microsoft Visual Studio 2012.

Espero que le sea de utilidad a alguien.

Enlace de descarga (3.2 Mb)

En esta entrada nada estelar, querría comentar un pequeño truquillo para quien se adentre en el fabuloso mundo de la programación contra Office 365.

En concreto, con respecto a la Url de Office 365.

Las cuentas de correo para Office 365 normalmente poseen un largo nombre del tipo xxxoffice365.onmicrosoft.com

De esta manera, accederemos al portal de Office 365 para nuestro usuario a un sitio del tipo portal.microsoftonline.com.

Sin embargo, cuando queremos crear una aplicación en Visual Studio para atacar o trabajar contra Office 365, nos surgirá una pregunta.

¿Qué Url es la que posee el servidor de nuestra empresa contra la que queremos trabajar?.

Una forma sencilla es acceder al portal de Office 365, y una vez en el portal, acceder a la url: http://mail.office365.com/.

Automáticamente nos llevará a una url del tipo: https://xxx.outlook.com/owa/

Así que si queremos acceder contra EWS (Exchange Web Services), lo único que tendremos que hacer, será cambiar esa url anterior por la que normalmente tendrá la descripción de los servicios, como por ejemplo:

https://xxx.outlook.com/ews/Services.wsdl

De esta manera, podremos acceder sin problemas a nuestro servicio de Exchange y a todos sus métodos y funciones.

Espero que le sirva a más de uno.

Publicado por Jorge Serrano | con no comments

Introducción

Si estás utilizando Visual Studio 2012 en Windows 8 y estás intentando conectar con Team Foundation Service (lo que antiguamente se llamaba TFS Preview), quizás hayas tenido la fabulosa experiencia de toparte con un error de tipo TF31003.

Si es así, esta entrada creo que podría ayudarte.

Al lío…

Supongamos que tenemos ya nuestro servicio de TFS creado y una dirección de tipo https://{nombre}.visualstudio.com

Iniciamos Visual Studio 2012 y nos encontramos con la siguiente pantalla:

Nuestra primera idea es la de conectarnos a Team Foundation Server, así que pulsamos sobre este enlace y obtenemos una nueva ventana donde deberemos establecer la conexión.

En mi caso no tengo ninguna conexión, así que deberé hacer clic sobre el botón Servers.

De esta manera aparecerá la siguiente ventana:

En mi caso no tengo ninguna conexión, así que deberé hacer clic sobre el botón Add.

En el caso de que tengáis ya conexiones creadas pero no con el server de TFS que queremos conectar, deberemos igualmente hacer clic sobre el botón Add.

Aquí aparecerá una nueva ventana en la que añadiremos la conexión a nuestro Team Foundation Server introduciendo la url de nuestro servicio: https://{nombre}.visualstudio.com

Una vez que tenemos todo listo, haremos clic al botón OK.

El proceso de autenticación se iniciará y obtendremos una ventana en blanco como la siguiente:

Después de unos segundos, aparecerá un mensaje en pantalla indicándonos que se ha producir un error de tipo TF31003.

Da igual que reiniciemos el ordenador, ya que el error persistirá.

En este punto, ¿cómo resolver el problema?.

Independientemente de que existan otras formas menos dañinas, la forma más sencilla es limpiar las Cookies del navegador Internet Explorer.

Basta hacer esto y repetir los pasos anteriores para comprobar que a la hora de pedir las credenciales de autenticación, la ventana sí se muestra correctamente.

Así que se puede decir que con esto, resolveremos el problema.

Espero que a alguno más le ayude.

Introducción

Hasta ahora, hemos visto como pasar de una aplicación de Software que cumple los requisitos a una aplicación de Software que cumple los requisitos, que es reutilizable y que mejora el mantenimiento de aplicaciones, llevándolo todo a un mundo ideal.

¿Pero es ese mundo ideal de desarrollo el mundo ideal de la oportunidad de negocio o de mercado?.

Cuando las prioridades se imponen al mundo ideal

Hablo de desarrollo del Software…

El problema hoy día de muchas empresas, por no decir todas, es la prioridad.

El riesgo o amenaza de una empresa es la competitividad de la competencia.

Y las incógnitas de la ecuación de toda empresa es el tiempo, los gastos y los ingresos.

Si mezclamos todos estos ingredientes en un mismo tarro, podemos obtener un cocktail de lo más explosivo.

En el mundo ideal, los desarrolladores queremos hacer un código bonito y que cumpla todas las posibles premisas de lo que es un desarrollo correcto, sin embargo, no siempre esto es posible.

La presión por terminar los proyectos en un corto plazo de tiempo, pensar en ingresar todo lo que se pueda y ofrecer unos gastos reducidos, hacen que el proyecto sea atractivo, la empresa ingrese un variable muy goloso y se vuelva a desarrollar otro producto. Así funcionan la mayoría de empresas de servicios hoy día. Es lo que mucha gente denomina como un modelo de negocio práctico.

Sin embargo, hay clientes (existen y los hay), que prefieren no ser tan “prácticos” y dedicar parte de los esfuerzos y dinero a lograr un sistema que recoja todas estas bondades. Y con ello, no se está queriendo decir que el proyecto haya sido más largo o más costoso entendiendo como coste los gastos o la diferencia entre ingresos menos gastos.

Muchas veces, pensamos que hacer proyectos que dispongan de todas estas posibilidades no es ventajoso, pero pensemos en que podemos estar delante de un proyecto cuyos requisitos cambian o se saben de antemano, que variarán en el tiempo y mucho,… quizás convenga hacer las cosas de la mejor forma posible.

No quiero indicar con todo esto que es mejor una forma de hacer los proyectos (por ejemplo en la parte I de este conjunto de entradas), o de la última forma aplicando estrictamente SOLID.

Me gustaría que este conjunto de entradas sirvieran de reflexión para indicar que ni existe el mundo ideal ni el mundo “no ideal” es malo.

Cada proyecto de Software es único, no me cansaré de repetirlo, y como tal, requiere un planteamiento concreto a la hora de abordarlo.

Muchas startups utilizan planteamientos ágiles para sacar adelante su producto, porque no buscan el cojo-producto, sino dar funcionalidad a una idea para ir comprobando como funciona y en su caso refinarla adecuadamente. Dentro de ese refinamiento, podrían encontrarse con la necesidad de rehacer su producto por completo, y eso siempre y cuando empiecen a tener éxito y mucho antes de que se convierta en cojo-producto como es obvio.

A veces debemos sacrificar mantenimiento y reutilización para llegar al mercado primeros y golpear antes.

Todo, absolutamente todo, es cuestión de prioridades, y nada nos hace más libres que tomar las decisiones que consideremos oportuno en cada momento, pudiendo saltar de una forma de abordar el producto a otra si con ello, tenemos después que rehacer el producto.

Introducción

En las entradas anteriores, vimos como desarrollar una aplicación a partir de un problema teóricamente trivial.

Los requisitos cambian y las necesidades empresariales nos llevan a ser ágiles y adoptar cambios de manera rápida y flexible, facilitar las pruebas unitarias y en definitiva, codificar código lo más limpio posible y con posibilidades de reutilizarlo.

Hemos llegado a un punto bastante aceptable pero no es suficiente. Al menos no para unos programadores exigentes como nosotros.

Y de esta manera, hemos llegado a mencionar un conjunto de principios básicos de programación orientada a objetos… bueno, en realidad cinco principios, que reciben el nombre de SOLID.

Así que en este punto, lo mejor es hacer una pequeña pausa y hablar de esos cinco principios que deberíamos tratar de cumplir siempre que sea posible con el fin de no perdernos más adelante.

¿Es obligatorio cumplirlos?. No, pero sí es recomendable cumplirlos todos. Sino podemos cumplir todos, cuantos más cumplamos, mejor.

Empecemos entonces…

SOLID

SOLID es un acrónimo de 5 principios básicos de programación orientada a objetos que surgieron alrededor del año 2000.

También lo escucharás citar como los principios SOLID.

Cada letra de la palabra SOLID corresponde a un principio:

  • SRP o Single Responsability Principle.
  • OCP u Open/Close Principle.
  • LSP o Liskov Substitution Principle.
  • ISP o Interface Segregation Principle.
  • DIP o Dependency Inversion Principle.

Lo mejor para entender cada uno de estos principios, es verlos de forma breve y concisa.

SRP o Single Responsability Principle

Es quizás el más fácil de entender.

El concepto detrás de este principio es el de tener en mente que cada clase tenga una única responsabilidad.

Esa responsabilidad debería estar contenida dentro de la clase.

Si tenemos la necesidad de encapsular una responsabilidad en varias clases, quizás nuestra clase estuviera haciendo más cosas de las que debiera y por lo tanto, deberíamos pensar en refactorizar nuestro código para mejorarlo y llegar a cumplir este principio.

Para este principio, sólo se exige atención a los requisitos, refinamiento si procede y sentido común a la hora de hacer las cosas.

Un ejemplo sencillo podría ser el siguiente:

Partimos de una clase Coche con diferentes comandos y funcionalidades. Básicamente y para no complicarlo, tenemos la posibilidad de arrancar el motor y apagarlo, y de acelerar y frenar.

Dos variables nos indican si el coche está arrancado así como su velocidad.

Desde el punto de responsabilidad única y a simple vista, la clase Coche hace bastantes cosas.

Podríamos mejorar por lo tanto todo esto para lograr algo parecido a (en aproximación):

No pongo el código porque creo que se entiende bien, y lo principal realmente aquí es el concepto de este principio.

Como se puede apreciar, además de separar responsabilidades, podemos hacer pruebas unitarias de cada una de estas partes por separado y de todas ellas conjuntamente.

No es quizás el mejor ejemplo, pero si sirve para aclarar el concepto, con eso me conformo.

OCP u Open/Close Principle

El concepto detrás de este principio dice que deberíamos codificar nuestras clases, funciones, métodos, etc., de forma abierta a su extensión y cerrada en su modificación.

Dicho así puede que suene etéreo, así que digámoslo de otra manera.

Nuestras clases, funciones, métodos, etc., deberían permitir que su comportamiento variara o cambiara sin que tengamos que modificar nuestro código fuente.

Un ejemplo sencillo podría ser el siguiente:

El código de este ejemplo demostrativo sería similar al siguiente:

   1:      using System;
   2:   
   3:   
   4:      public class Rectangulo
   5:      {
   6:          public double Alto { get; set; }
   7:          public double Ancho { get; set; }
   8:      } // Rectangulo
   9:   
  10:      public class Circulo
  11:      {
  12:          public double Radio { get; set; }
  13:      } // Circulo
  14:   
  15:      public class CalculoArea
  16:      {
  17:          
  18:          public double GetArea(Circulo circulo)
  19:          {
  20:              return Math.PI * Math.Pow(circulo.Radio, 2);
  21:          } // GetArea
  22:          
  23:          public double GetArea(Rectangulo rectangulo)
  24:          {
  25:              return rectangulo.Alto * rectangulo.Ancho;
  26:          } // GetArea
  27:   
  28:      } // CalculoArea

Y si queremos consumir estas clases en nuestra aplicación, emplearíamos un código similar al siguiente:

   1:  CalculoArea calculoArea = new CalculoArea();
   2:  Circulo circulo = new Circulo();
   3:  circulo.Radio = 13;
   4:  Rectangulo rectangulo = new Rectangulo();
   5:  rectangulo.Alto = 3;
   6:  rectangulo.Ancho = 7;
   7:  MessageBox.Show(calculoArea.GetArea(circulo).ToString());
   8:  MessageBox.Show(calculoArea.GetArea(rectangulo).ToString());

Como podemos apreciar aquí, el ejemplo que hemos desarrollado parece estar bien. De hecho, funciona y hace lo que esperamos que haga. Así que desde el punto de vista de requisitos lo podríamos dar por bueno.

Sin embargo, si prestamos atención a lo que hemos hecho, veremos que hay algo que nos chirría… o debería chirriarnos… ¿os acordáis del primer principio SOLID?. ¿Ese que trata sobre la responsabilidad simple?. Cuando un principio no se cumple, decimos que violamos ese principio, algo que estamos haciendo aquí.

Tenemos un objeto de cálculo del área que calcula todas las áreas habidas Y POR HABER, es decir, si decidimos agregar una nueva figura geométrica para calcular su área, nos veremos obligado a modificar la clase CalculoArea.

El caso es que podríamos mejorar lo presente (quizás) dando una vuelta de tuerca.

Imaginemos entonces el siguiente diagrama de objetos refactorizando lo anterior:

Aunque a priori hemos mejorado el mantenimiento de nuestra aplicación, sabemos ya a estas alturas que no estamos delante de un marco ideal de cómo hacer las cosas. Así que si incrementamos las figuras geométricas, estaremos nuevamente delante de la necesidad de agregar otra variable dentro de la clase CalculoArea para la nueva figura geométrica además de tener que agregar en la función GetArea su correspondiente cálculo.

En resumidas cuentas, que estaremos más o menos igual que antes.

Parece evidente analizando nuestro código, que todas las figuras geométricas tienen en común algo. La necesidad o el requisito de calcular su área, nada mejor como su propia figura geométrica para saber y conocer perfectamente cuál es el cálculo de su área.

Pero aún mucho mejor si abstraemos esa funcionalidad de manera tal que si agregamos una nueva figura, cumpla con ese requisito.

El siguiente diagrama recoge esta filosofía:

Y el código de esta implementación quedaría de la siguiente manera:

   1:      using System;
   2:   
   3:   
   4:      public interface IFiguraGeometrica
   5:      {
   6:          double GetArea();
   7:      } // IFiguraGeometrica
   8:   
   9:   
  10:      public class Cuadrado : IFiguraGeometrica
  11:      {
  12:   
  13:          public Cuadrado(double lado)
  14:          {
  15:              this.Lado = lado;
  16:          } // Circulo Constructor
  17:   
  18:          private double Lado { get; set; }
  19:   
  20:          public double GetArea()
  21:          {
  22:              return Math.Pow(this.Lado, 2);
  23:          } // GetArea
  24:   
  25:      } // Cuadrado
  26:   
  27:      public class Circulo : IFiguraGeometrica
  28:      {
  29:   
  30:          public Circulo(double radio)
  31:          {
  32:              this.Radio = radio;
  33:          } // Circulo Constructor
  34:   
  35:          private double Radio { get; set; }
  36:   
  37:          public double GetArea()
  38:          {
  39:              return Math.PI * Math.Pow(this.Radio, 2);
  40:          } // GetArea
  41:   
  42:      } // Circulo
  43:   
  44:      public class Rectangulo : IFiguraGeometrica
  45:      {
  46:   
  47:          public Rectangulo(double ancho, double alto)
  48:          {
  49:              this.Ancho = ancho;
  50:              this.Alto = alto;
  51:          } // Rectangulo Constructor
  52:   
  53:          private double Ancho { get; set; }
  54:          private double Alto { get; set; }
  55:   
  56:          public double GetArea()
  57:          {
  58:              return this.Alto * this.Ancho;
  59:          } // GetArea
  60:   
  61:      } // Rectangulo

Y una aproximación de utilizar esto quedaría de la siguiente manera aproximada:

   1:  IFiguraGeometrica figuraGeometrica = new Circulo(13);
   2:  MessageBox.Show(figuraGeometrica.GetArea().ToString());
   3:  figuraGeometrica = new Rectangulo(7, 3);
   4:  MessageBox.Show(figuraGeometrica.GetArea().ToString());

Evidentemente, todo esto como podemos ver resulta mucho más simple.

Si modificamos una implementación de Cuadrado, Circulo o Rectangulo, no estaremos “rompiendo” nada de lo que ya existe.

Mejoraremos el mantenimiento, e incorporaremos pautas para reutilizar el código.

LSP o Liskov Substitution Principle

Este principio viene a decir que los objetos de una aplicación deberían ser reemplazables con instancias de sus subtipos sin que por ello tengamos que alterar el funcionamiento y la lógica de la aplicación.

Dicho de otro modo, que las funciones que utilizan referencias o punteros a clases base, deberían ser capaces de utilizar los objetos de las clases derivadas sin conocerlas.

Veámoslo con un ejemplo de aproximación partiendo del siguiente diagrama:

Y el código fuente de lo que estamos viendo quedaría de la siguiente manera:

   1:  public class Cuadrado : Rectangulo
   2:      {
   3:   
   4:          public override double Ancho
   5:          {
   6:              get
   7:              {
   8:                  return base.Ancho;
   9:              }
  10:              set
  11:              {
  12:                  base.Ancho = value;
  13:                  base.Alto = value;
  14:              }
  15:          } // Ancho
  16:   
  17:          public override double Alto
  18:          {
  19:              get
  20:              {
  21:                  return base.Alto;
  22:              }
  23:              set
  24:              {
  25:                  base.Ancho = value;
  26:                  base.Alto = value;
  27:              }
  28:          } // Alto
  29:   
  30:      } // Cuadrado
  31:   
  32:      public class Rectangulo
  33:      {
  34:          public virtual double Ancho { get; set; }
  35:          public virtual double Alto { get; set; }
  36:   
  37:          public double GetArea()
  38:          {
  39:              return this.Ancho * this.Alto;
  40:          } // GetArea
  41:   
  42:      } // Rectangulo

El consumo de este ejemplo quedaría de la siguiente forma:

   1:  Rectangulo rectangulo = new Cuadrado();
   2:  rectangulo.Alto = 3;
   3:  rectangulo.Ancho = 7;
   4:  MessageBox.Show(rectangulo.GetArea().ToString());

El resultado esperado de este cálculo sería 21, sin embargo, obtendremos 49 que sería el producto de 7 x 7, algo que en el caso del cálculo del rectángulo no es lo que esperábamos.

¿Cómo resolver el problema?.

Una posibilidad sería la siguiente:

En código, este planteamiento quedaría de la siguiente forma:

   1:      public class Dimensiones
   2:      {
   3:          
   4:          public virtual double Ancho { get; set; }
   5:          public virtual double Alto { get; set; }
   6:   
   7:          public double GetArea()
   8:          {
   9:              return this.Ancho * this.Alto;
  10:          } // GetArea
  11:   
  12:      } // Dimensiones
  13:   
  14:      public class Cuadrado : Dimensiones
  15:      {
  16:   
  17:          public override double Ancho
  18:          {
  19:              get
  20:              {
  21:                  
  22:                  return base.Ancho;
  23:              }
  24:              set
  25:              {
  26:                  base.Alto = value;
  27:                  base.Ancho = value;
  28:              }
  29:          } // Ancho
  30:   
  31:          public override double Alto
  32:          {
  33:              get
  34:              {
  35:                  return base.Alto;
  36:              }
  37:              set
  38:              {
  39:                  base.Alto = value;
  40:                  base.Ancho = value;
  41:              }
  42:          } // Alto
  43:   
  44:      } // Cuadrado
  45:   
  46:      public class Rectangulo : Dimensiones
  47:      {
  48:      } // Rectangulo

Consumir nuestras clases ahora quedaría de la siguiente manera:

   1:  Dimensiones figura = new Rectangulo();
   2:  figura.Alto = 3;
   3:  figura.Ancho = 7;
   4:  MessageBox.Show(figura.GetArea().ToString());

De esta manera y con este ejemplo, aproximamos una solución a los problemas planteados.

ISP o Interface Segregation Principle

Este principio nos indica que los clientes no deberían ser forzados a implementar interfaces que no van a utilizar.

Deberíamos tener en cuenta que si tenemos una interfaz bastante grande, deberíamos pensar en segregarla en varias más pequeñas y específicas.

Un ejemplo práctico de esto que estamos comentando en la siguiente interfaz:

Esta interfaz tiene tres métodos muy sencillos a modo de ejemplo:

   1:      public interface IDesplazarse
   2:      {
   3:          void Conducir();
   4:          void Correr();
   5:          void Pasar();
   6:      } // IDesplazarse

Sin embargo, aquí nos encontramos con una característica a tener en cuenta.

Un ser humano que va a desplazarse no tiene porqué saber conducir, o incluso a lo mejor, no tiene edad suficiente para conducir.

Imaginemos un niño de 15 años. Podrá pasear y podrá correr, pero no podrá conducir.

Así que nuestra interfaz es correcta para otro grupo de personas que cumplan todos los requisitos de la interfaz o sobre las que queramos ejecutar el método de Conducir, pero si tuviéramos una clase Persona que implementara IDesplazarse y que no pudiera conducir, se produciría una excepción ya que no hemos implementado dicha funcionalidad.

Es decir, deberíamos segregar la interfaz en más de una interfaz de acuerdo a nuestras necesidades. Y en este caso, nuestra solución quedaría de la siguiente manera:

Y el código de esta nueva implementación quedaría de la siguiente manera:

   1:      public interface IDesplazarse
   2:      {
   3:          void Correr();
   4:          void Pasar();
   5:      } // IDesplazarse
   6:   
   7:      public interface IDesplazarseConCarnetConducir : IDesplazarse
   8:      {
   9:          void Conducir();
  10:      } // IDesplazarseConCarnetConducir

Como podemos apreciar, tendremos personas que utilicen la interfaz IDesplazarse y otras que además de desplazarse conduzcan, por lo que implementarán la interfaz IDesplazarseConCarnetConducir que implementará a su vez IDesplazarse.

DIP o Dependency Inversion Principle

En este principio se enuncia que deberíamos depender de las abstracciones y no de las implementaciones. Las abstracciones no deberían depender de los detalles.

Por otro lado, Dependency Injection o Inyección de Dependencias es un método que nos permite cumplir con este principio.

Pero ciñéndonos a los ejemplos, vamos a aproximar una comprensión sobre DIP.

El diagrama que recogería esta filosofía sería el siguiente:

El código del diagrama anterior es el que se indica a continuación:

   1:      public interface IValidator
   2:      {
   3:          bool Validate();
   4:      } // IValidator
   5:   
   6:      public class ValidationManager
   7:      {
   8:          private IValidator validator;
   9:   
  10:          public ValidationManager(IValidator validator)
  11:          {
  12:              this.validator = validator;
  13:          } // ValidationManager
  14:   
  15:          public void Execute()
  16:          {
  17:              if (!this.validator.Validate())
  18:              {
  19:                  // Do Something
  20:              }
  21:          } // Execute
  22:   
  23:      } // ValidationManager

Como podemos ver aquí, dependemos de las abstracciones en lugar de las implementaciones, y todas las referencias están basadas en interfaces.

Independientemente del ejemplo anterior, también podríamos utilizar el patrón factoría (Factory Pattern) con el fin de resolver a través de ese patrón, todas las dependencias.

Introducción

Seguimos avanzando en nuestro desarrollo mejorándolo poco a poco.

Esto me recuerda a aquellos maravillosos años de la normalización de nuestras bases de datos para llegar a tercera forma normal (3NF) o llegar al éxtasis con Boyce-Codd.

Implementación de la solución

En este caso, la implementación de nuestra solución partiendo del código anterior nos sugiere partir el código en módulos o de una forma tal que nos permita depurar y mantener mejor nuestra aplicación, al mismo tiempo que podemos abordar la posibilidad de reutilizar el código.

Para llevar a cabo nuestro propósito, hemos creado un proyecto en Visual Studio que será una biblioteca de clases a la que he llamado Foo.Framework.

Dentro de este proyecto, vamos a crear nuestra lista enumerada que ya vimos en la entrada anterior, y un objeto que se encargará de llevar a cabo el proceso de lectura y escritura de ficheros de texto y documentos Excel.

Dicho de otro modo, vamos a separar algunas responsabilidades iniciales de modo que aporte diferentes beneficios.

La lista enumerada se llamará ConnectorType y tendrá este aspecto:

El código de esta lista enumerada corresponderá con lo que se indica a continuación:

   1:  namespace Foo.Framework
   2:  {
   3:   
   4:      public enum ConnectorType
   5:      {
   6:          Excel,
   7:          Text
   8:      } // ConnectorType
   9:   
  10:  } // Foo.Framework

El código dentro del cuál vamos a trabajar con ficheros de texto y documentos Excel estará alojado en una clase de nombre ConnectorProcess:

El código de esta clase es el que se indica a continuación:

   1:  namespace Foo.Framework
   2:  {
   3:   
   4:      using System;
   5:   
   6:   
   7:      public sealed class ConnectorProcess
   8:      {
   9:   
  10:          public ConnectorProcess(ConnectorType connectorType)
  11:          {
  12:              this.Connector = connectorType;
  13:          } // ConnectorProcess Constructor
  14:   
  15:          private ConnectorType Connector { get; set; }
  16:   
  17:          public string Read()
  18:          {
  19:              switch (this.Connector)
  20:              {
  21:                  case ConnectorType.Excel:
  22:                      // Excel
  23:                      return "Excel leída";
  24:                      // Hacemos algo con la información leída.
  25:                      // ...
  26:                      break;
  27:                  default:
  28:                      // Texto
  29:                      return "Texto leído";
  30:                      // Hacemos algo con el texto leído.
  31:                      // ...
  32:                      break;
  33:              }
  34:              return String.Empty;
  35:          } // Read
  36:   
  37:          public void Write()
  38:          {
  39:              switch (this.Connector)
  40:              {
  41:                  case ConnectorType.Excel:
  42:                      // Excel
  43:                      // Escribimos Excel.
  44:                      break;
  45:                  default:
  46:                      // Texto
  47:                      // Escribimos Texto.
  48:                      break;
  49:              }
  50:          } // Write
  51:   
  52:      } // ConnectorProcess
  53:   
  54:  } // Foo.Framework

Y finalmente, nuestra interfaz de usuario.

No queda otra de momento, que crear una vinculación fuerte entre nuestra interfaz de usuario y Foo.Framework, ya que vamos a utilizar las clases que tenemos dentro de ese ensamblado.

Habiendo incluido una referencia a Foo.Framework, lo que tenemos que hacer es escribir el código de nuestra aplicación y que tendrá el siguiente aspecto:

   1:  namespace UI_Sample
   2:  {
   3:   
   4:      using System;
   5:      using System.Collections.Generic;
   6:      using System.ComponentModel;
   7:      using System.Drawing;
   8:      using System.Windows.Forms;
   9:   
  10:      using Foo.Framework;
  11:   
  12:   
  13:      public partial class MainForm : Form
  14:      {
  15:   
  16:          public MainForm()
  17:          {
  18:              InitializeComponent();
  19:              // Por defecto es un fichero de texto.
  20:              this.Connector = ConnectorType.Excel;
  21:          } // MainForm Constructor
  22:   
  23:          public ConnectorType Connector { get; set; }
  24:   
  25:          private void btnSampleTest_Click(object sender, EventArgs e)
  26:          {
  27:              ConnectorProcess connectorProcess = new ConnectorProcess(this.Connector);
  28:              // Leemos la información.
  29:              string data = connectorProcess.Read();
  30:              // Escribimos el resultado del supuesto proceso anterior.
  31:              connectorProcess.Write();
  32:              // Mostramos un mensaje en pantalla tipo fake.
  33:              MessageBox.Show(
  34:                              data +
  35:                              Environment.NewLine +
  36:                              "Lectura y escritura realizada.");
  37:          } // btnSampleTest_Click
  38:          
  39:      } // MainForm
  40:   
  41:  } // UI_Sample

Como podemos apreciar, el código de nuestra interfaz de usuario se ha reducido bastante y está ahora quizás, mucho más claro que antes.

Posibles problemas

Hemos mejorado mucho algunos de los problemas detectados en las fases de desarrollo iniciales, y no decimos nada con respecto a como empezamos el proyecto y como está ahora. Sin embargo, seguimos teniendo problemas y se nos siguen ocurriendo mejoras.

El problema más molesto es quizás que nuestra interfaz de usuario tiene una relación fuerte con nuestro ensamblado Foo.Framework.

Por otro lado algo resuena en nuestras cabezas… algo denominado como principios básicos de programación orientada a objetos… en una sola palabra: Los principios SOLID.

Retomando la idea que indiqué al principio sobre 3NF y Boyce-Codd con respecto al modelado de una base de datos, SOLID es para mí su espejo con respecto a la programación orientada a objetos.

Cierto es que si queremos, podemos preparar una base de datos sin normalizar y que podemos trabajar con ella sin necesidad de llegar a 3FN o Boyce-Codd, pero que duda cabe que evitaremos problemas a largo plazo si la tenemos normalizada correctamente desde un principio.

También y por similitud, podemos desarrollar una aplicación Software sin tener en cuenta ningún principio SOLID, pero que duda cabe, que tenerlos presentes todos y cumplirlos, nos aportará beneficios notables de mantenimiento y reutilización.

La idea principal es la de adaptar nuestra aplicación a los cambios, ser ágiles ante esos cambios, y tratar de evitar que dichos cambios afecten a otras partes de la aplicación.

Pero quizás antes de seguir mejorando nuestro ejemplo, debamos hacer una pequeña pausa en el camino…

Introducción

Nos encontramos en una encrucijada.

Nuestra aplicación parecía sencilla y empezó siéndolo, pero los requisitos inicialmente marcados han variado y nos está empezando a dar algún que otro dolor de cabeza.

No obstante, hemos sabido adaptarnos a esos requisitos y hemos modificado nuestra aplicación para cubrirlos.

Implementación de la solución

La idea inicial es la de partir del código de la entrada anterior, refactorizar o acondicionar de forma general el código para que cumpla los requisitos de forma aceptable y posibilite un mejor mantenimiento del código.

Basándonos aún en una aplicación Windows, nuestro código quedará de la siguiente forma.

En primer lugar, la lista enumerada:

   1:  namespace UI_Sample
   2:  {
   3:   
   4:      public enum ConnectorType
   5:      {
   6:          Excel,
   7:          Text
   8:      } // ConnectorType
   9:   
  10:  } // UI_Sample

Como podemos ver en el código anterior, nuestra clase enumerada tiene dos valores, uno para definir los ficheros de tipo Excel y otro para los de tipo Text o texto.

De esta manera, podremos indicar el origen y destino de forma más flexible.

El código de nuestra aplicación Windows quedará ahora de la siguiente forma:

   1:  namespace UI_Sample
   2:  {
   3:   
   4:      using System;
   5:      using System.Collections.Generic;
   6:      using System.ComponentModel;
   7:      using System.Drawing;
   8:      using System.Windows.Forms;
   9:   
  10:      public partial class MainForm : Form
  11:      {
  12:   
  13:          public MainForm()
  14:          {
  15:              InitializeComponent();
  16:              // Por defecto es un fichero de texto.
  17:              this.Connector = ConnectorType.Text;
  18:          } // MainForm Constructor
  19:   
  20:          public ConnectorType Connector { get; set; }
  21:   
  22:          private void btnSampleTest_Click(object sender, EventArgs e)
  23:          {
  24:              string data = String.Empty;
  25:              // Leemos la información.
  26:              data = Read();
  27:              // Escribimos el resultado del supuesto proceso anterior.
  28:              Write();
  29:              // Mostramos un mensaje en pantalla tipo fake.
  30:              MessageBox.Show(
  31:                              data +
  32:                              Environment.NewLine +
  33:                              "Lectura y escritura realizada.");
  34:          } // btnSampleTest_Click
  35:   
  36:          private string Read()
  37:          {
  38:              switch (this.Connector)
  39:              {
  40:                  case ConnectorType.Excel:
  41:                      // Excel
  42:                      return "Excel leída";
  43:                      // Hacemos algo con la información leída.
  44:                      // ...
  45:                      break;
  46:                  default:
  47:                      // Texto
  48:                      return "Texto leído";
  49:                      // Hacemos algo con el texto leído.
  50:                      // ...
  51:                      break;
  52:              }
  53:              return String.Empty;
  54:          } // Read
  55:   
  56:          private void Write()
  57:          {
  58:              switch (this.Connector)
  59:              {
  60:                  case ConnectorType.Excel:
  61:                      // Excel
  62:                      // Escribimos Excel.
  63:                      break;
  64:                  default:
  65:                      // Texto
  66:                      // Escribimos Texto.
  67:                      break;
  68:              }
  69:          } // Write
  70:          
  71:      } // MainForm
  72:   
  73:  } // UI_Sample

Hemos preparado una propiedad para indicar el tipo de conector a utilizar.

Y posteriormente hemos llamado a una función Read y a un método Write para llevar a cabo nuestras acciones.

Indudablemente el código tiene un carácter meramente descriptivo porque faltarían más cosas como implementar la lógica de lectura y otras partes importantes de nuestra solución, pero lo importante aquí es quedarnos con la idea.

Posibles problemas

Empezamos con una aplicación para procesar archivos de texto.

Más tarde, los requisitos cambiaron y nos pedían procesar archivos de texto y Excel. Hicimos los cambios, pero nos dimos cuenta que de cara al mantenimiento, podríamos tener algún que otro quebradero de cabeza, así que hemos pensado en refactorizar un poco el código y mejorar algunas cosas.

Así surge esta tercera revisión que mejora aspectos relacionados con el mantenimiento. Además, si alguien nos pide ahora agregar otro conector como por ejemplo uno para leer y escribir en base de datos, bastará con agregar un nuevo elemento a nuestra lista enumerada y modificar Read y Write para que procesen también entradas y salidas con bases de datos.

Parece que todo está más o menos acorde con lo que buscamos, pero tenemos delante de nosotros varios problemas bastante más graves que a simple vista muchas veces no vemos.

Por un lado la separación de responsabilidades. Aquí el lema es divide y vencerás. Si queremos hacer algo que nos va a llevar mucho tiempo o proceso, lo mejor es separar en unidades pequeñas cada una de esas actividades. Pensemos por poner un ejemplo, en una línea de montaje.

Por otro lado, y en el caso de que hiciéramos pruebas unitarias, la posibilidad de probar las porciones de código por separado y centrando los esfuerzos y dedicación únicamente en aquellas unidades de Software que realmente cambian sin que estas afecten a un todo. Pensemos en que alguna parte de nuestro Software se modifica, como por ejemplo que aparece una nueva versión de Excel que afecta como es lógico al proceso de documentos Excel. Si el resto de código de nuestra aplicación funciona perfectamente, la forma en la que hemos codificado nuestra aplicación nos obliga lo queramos o no, a tocar una parte de código que entremezcla cosas que funcionan y otras que no. Además de que puede haber diferentes personas tocando el mismo código y que existen herramientas que lo permiten, es cierto que es un foco de problemas, y además, es posible que toquemos accidentalmente código que funcionaba, por lo que podemos crear nuevos problemas.

Otro aspecto a destacar y no menos importante, tiene que ver con la dependencia. Y es que nuestra aplicación depende fuertemente de unas piezas de Software que entremezclan UI con lógica de negocio y no sólo ensucian nuestro desarrollo, sino que enmaraña el mantenimiento de la misma y dificulta su depuración.

Y todo esto sin poner encima de la mesa otro de los problemas más habituales y que siempre pensamos en ellos al final, la reutilización del código realizado. En este caso, al estar todo integrado dentro de una misma aplicación como es la interfaz de usuario, su reutilización se nos antoja al menos, compleja.

¿Qué hacer entonces?. ¿Cómo resolver estos problemas?.

En la próxima entrada veremos como resolver alguno de estos problemas.

Introducción

Como vimos en el artículo inicial, nos encontramos con un problema sencillo de resolver pero que poco a poco se iba retorciendo o complicando.

Inicialmente teníamos en mente la lectura de un fichero de texto y la escritura de una información determinada después de procesarla en un fichero de texto.

Sin embargo, los requisitos cambian y ahora se nos pide que además de leer y escribir un fichero de texto, hagamos lo mismo pero con un fichero de Excel.

En realidad sería hacer algo similar a lo siguiente:

Implementación de la solución

Suponiendo que tengamos toda la lógica en nuestro formulario de prueba (igualmente ocurriría si tuviéramos toda la lógica implementada en una biblioteca de clases aunque los problemas estarían más acusados en el caso de tener todo implementado la interfaz de usuario), el código quedaría en este caso de la siguiente manera:

   1:  namespace UI_Sample
   2:  {
   3:   
   4:      using System;
   5:      using System.Collections.Generic;
   6:      using System.ComponentModel;
   7:      using System.Drawing;
   8:      using System.Windows.Forms;
   9:   
  10:      public partial class MainForm : Form
  11:      {
  12:   
  13:          public MainForm()
  14:          {
  15:              InitializeComponent();
  16:              // Por defecto es un fichero de texto.
  17:              this.EsTexto = true;
  18:          } // MainForm Constructor
  19:   
  20:          public bool EsTexto { get; set; }
  21:   
  22:          private void btnSampleTest_Click(object sender, EventArgs e)
  23:          {
  24:              string data = String.Empty;
  25:              if (this.EsTexto)
  26:              {
  27:                  // Texto
  28:                  data = ReadText();
  29:                  // Hacemos algo con el texto leído.
  30:                  // ...
  31:                  // Escribimos el resultado del supuesto proceso anterior.
  32:                  WriteText();
  33:              }
  34:              else
  35:              {
  36:                  // Excel
  37:                  data = ReadExcel();
  38:                  // Hacemos algo con la información leída.
  39:                  // ...
  40:                  // Escribimos el resultado del supuesto proceso anterior.
  41:                  WriteExcel();
  42:              }
  43:              // Mostramos un mensaje en pantalla tipo fake.
  44:              MessageBox.Show(
  45:                              data +
  46:                              Environment.NewLine +
  47:                              "Lectura y escritura realizada.");
  48:          } // btnSampleTest_Click
  49:   
  50:          private string ReadText()
  51:          {
  52:              // Abrimos el fichero y leemos su contenido.
  53:              return "Texto leido";
  54:          } // ReadText
  55:   
  56:          private void WriteText()
  57:          {
  58:              // Escribimos el fichero en su lugar destino.
  59:          } // WriteText
  60:   
  61:          private string ReadExcel()
  62:          {
  63:              // Abrimos Excel y leemos su contenido.
  64:              return "Excel leída";
  65:          } // ReadExcel
  66:   
  67:          private void WriteExcel()
  68:          {
  69:              // Escribimos el Excel en su lugar destino.
  70:          } // WriteExcel
  71:   
  72:      } // MainForm
  73:   
  74:  } // UI_Sample

Posibles problemas

Aunque lo esté exagerando un poco, la idea es la de presentar delante nuestra diferentes problemas cotidianos con los que podemos encontrarnos a la hora de desarrollar una solución a un problema planteado.

En este caso, vemos que el código se está empezando a volver insoportable de mantener.

En este punto, tenemos una variable booleana que nos va a permitir discriminar entre un fichero de texto y un documento Excel.

No siendo la mejor de las soluciones, es hasta cierto punto aceptable.

Sin embargo, ¿qué ocurre si además de Excel y texto necesitamos acceder a la información de una tabla por ejemplo para leer determinada información, procesarla y volver a almacenarla en otra tabla?.

Bien, nuestra propiedad bool la podemos hacer nullable y así tendremos tres valores, true, false y null.

Posible chapuza a la vista aunque bien, es una posible solución.

Otra posible solución es crear una lista enumerada y a partir de ella determinar el tipo de origen, destino que queremos utilizar.

Es quizás una solución más elegante.

Otra es crear una llamada por cada tipo y que se cree el objeto de cada tipo para el objetivo de nuestra aplicación, y bien… quizás así podamos llevar a cabo una solución más o menos gloriosa.

De hecho, en la próxima entrega voy a ajustar todo esto que estoy comentando para sacar adelante algo que resulte un poco más claro a la hora de leer el código… a ver si lo logro y seguimos avanzando viendo problemas y posibles soluciones.

Hasta la próxima entrega… :)

Introducción

No me voy a andar con grandes tecnicismos, más bien todo lo contrario.

Voy a ir directo al asunto y de forma concisa, planteando los problemas habituales con los que podemos encontrarnos los desarrolladores y cómo hacerlos frente.

Como avanzar y mejorar nuestro código basándonos en un proyecto teórico inicial y como ir salvando los diferentes obstáculos con los que podemos encontrarnos.

¿Seremos capaces?… ¡veámoslo!.

Punto de partida

Partiremos de un ejemplo muy sencillo de entender.

Empieza el proyecto de desarrollo y nos dicen que preparemos una aplicación que lea como entrada el contenido de un fichero de texto, y como salida, que escriba también en un fichero de texto.

Vamos a obviar de momento el proceso intermedio.

Sería algo similar a lo que se indica en la siguiente imagen:

Como podemos apreciar… algo muy sencillito de realizar.

Implementación de partida

Ante esto, la idea parece muy clara y evidente.

Vamos a crear un proyecto de aplicación Windows y sobre él vamos a llevar a cabo nuestro desarrollo.

Dentro del formulario Windows hemos insertado un control Button.

Todo muy sencillo.

El código quedaría de la siguiente manera:

   1:  namespace UI_Sample
   2:  {
   3:   
   4:      using System;
   5:      using System.Collections.Generic;
   6:      using System.ComponentModel;
   7:      using System.Drawing;
   8:      using System.Windows.Forms;
   9:   
  10:      public partial class MainForm : Form
  11:      {
  12:   
  13:          public MainForm()
  14:          {
  15:              InitializeComponent();
  16:          } // MainForm Constructor
  17:   
  18:          private void btnSampleTest_Click(object sender, EventArgs e)
  19:          {
  20:              string data = Read();
  21:              // Hacemos algo con el texto leído.
  22:              // ...
  23:              // Escribimos el resultado del supuesto proceso anterior.
  24:              Write();
  25:              // Mostramos un mensaje en pantalla tipo fake.
  26:              MessageBox.Show(
  27:                  data +
  28:                  Environment.NewLine +
  29:                  "Lectura y escritura realizada.");
  30:          } // btnSampleTest_Click
  31:   
  32:          private string Read()
  33:          {
  34:              // Abrimos el fichero y leemos su contenido.
  35:              return "Texto leido";
  36:          } // Read
  37:   
  38:          private void Write()
  39:          {
  40:              // Escribimos el fichero en su lugar destino.
  41:          } // Write
  42:   
  43:      } // MainForm
  44:   
  45:  } // UI_Sample

Posibles problemas

La solución anterior no está mal, sin embargo, puede presentarnos a futuro una serie de problemas que dependiendo de la complejidad del proyecto y otras circunstancias como por ejemplo si el código de nuestra aplicación cambia frecuentemente, etc., puede acarrearnos serios contratiempos.

Por otro lado, el principal problema que aporta el ejemplo anterior, sería el mantenimiento de la solución propuesta.

Mezclar lógica e interfaz de usuario debería ponernos los pelos como escarpias de antemano.

En otro orden de cosas, separar la lógica en una biblioteca de clases para apartarla de la interfaz de usuario, podría resolver parte de este problema, pero se nos presentación otro adicional.

¿Qué ocurriría si en lugar de querer leer desde un fichero de texto y escribir en un fichero de texto queremos cambiar ese fichero de texto por una hoja Excel?.

Esto es lo que resolveremos en la siguiente parte del artículo siguiendo con la inercia de desarrollo marcada aquí.

Introducción

El título es un poco largo, sí, ya lo sé, pero viene al caso de una serie de problemas que me han ocurrido y que he resuelto uno detrás de otro.

Comento la situación.

En mi mano he tenido tres terminales móviles con Windows Phone 7 (un LG E900 Windows 7 y dos Nokia Lumia 800).
Ambos han funcionado perfectamente, pero les he hecho alguna que otra perrería como es lógico.
Entre esas perrerías, reiniciarlos, resetearlos, actualizar firmwares, etc.

Todos los he registrado y desbloqueado para depurar aplicaciones Windows Phone desde mi Visual Studio, pero durante todo ese proceso, he cometido algún error que otro que he descubierto ahora y del que aquí expongo la solución.


Desbloqueo de un Windows Phone

Sólo a modo informativo y para aquel que no lo sepa, para desbloquear un Windows Phone y poder depurar aplicaciones Windows Phone en Visual Studio, deberemos desbloquearlo.

Para desbloquearlo, Microsoft proporciona una aplicación denominada Windows Phone Developer Registration, que puede ser encontrada en el SDK de Windows Phone 7 ó Windows Phone 8.

Esta herramienta detectará si tenemos conectado un Windows Phone 7 ó un Windows Phone 8.

Al hacer clic sobre registrar nuestro dispositivo, el proceso de desbloqueo se iniciará.

Si todo va bien, veremos que aparecerá un mensaje indicándonos que nuestro dispositivo ha sido registrado correctamente, sin embargo y en mi caso, me indica que ya tengo un dispositivo desbloqueado con el mismo nombre.


Mi primer error

Mi primer error ha sido llamar al terminal Nokia Lumia 800 igual que mi antecesor LG E900 Windows 7.
El LG está de backup ahora mismo, pero fue mi primer Windows Phone y con él he estado trasteando con Visual Studio y demás.

El hecho es que a la hora de registrar mi dispositivo, la herramienta de desbloqueo detecta, como decía anteriormente, que ya tengo registrado un dispositivo con el mismo nombre.

¿Cómo resolver este problema?.

La solución más sencilla no es la más óptima, y consistiría en reiniciar el terminal a fábrica y una vez así, cambiar el nombre del dispositivo. Otra posible solución sería sincronizar con Zune por primera vez el terminal y cambiar el nombre del terminal ahí, pero hay una solución más elegante que veremos a continuación.

El caso es que si acudimos a la web de Microsoft de Windows Phone (https://www.windowsphone.com) y accedemos con nuestra cuenta Passport, observaremos que en la sección Account settings de nuestra cuenta, encontraremos todos los dispositivos registrados para esa cuenta.

Lo sorprendente en mi caso, es que tengo dos dispositivos móviles con el mismo nombre.

Y claro, no tengo ninguna gana de reiniciar mi terminal a su estado inicial de fábrica.

Si accedo al terminal, tampoco encuentro dentro ninguna posibilidad para cambiar el nombre de ningún terminal, y en esta web tampoco encuentro nada.

Bien... pues como decía antes, hay una forma cómoda y elegante para resolver este problema.


Solución al primer problema

La solución consiste en acudir a Zune y dentro de Zune y con el dispositivo conectado (obviamente), ir a Setting del dispositivo.

Dentro de la configuración del dispositivo, acudiremos a la opción NAME YOUR PHONE, y allí, podremos ver el nombre actual de nuestro dispositivo y cambiar su nombre.

Ala,... ya estamos listos para desbloquear nuestro dispositivo móvil, así que volvemos a ejecutar el proceso de la herramienta Windows Phone Developer Registration.


Mi segundo error

Antes comenté que había estado trasteando con diferentes dispositivos móviles y con Visual Studio, así que eso significa que he desbloqueado una gran cantidad de dispositivos móviles con mi cuenta Passport.

Algo en lo que no he reparado...

El caso es que después de volver a ejecutar la herramienta de desbloqueo del terminal, me encuentro con otro mensaje nuevo.

En este caso, el problema es que tenemos desbloqueados más terminales de los que podemos.

Así que acudo a la Web anterior y trato de eliminar aquellos terminales que ya no uso dentro de la sección Account settings, y vuelvo a intentarlo, pero nada... sigo en las mismas.

Sin embargo, y una vez más... hay solución y no es esta última, sino otra nueva y diferente. ;)


Solución al segundo problema

La solución a este segundo problema no reside en ir a la Web que indicaba anteriormente, sino en ir a otra Web diferente que desde mediados del año 2012, sustituye al App Hub de Microsoft.

Esta Web es la web de desarrollo de Windows Phone (https://dev.windowsphone.com).

En esta web podemos subir nuestras aplicaciones Windows Phone, descargar el SDK para desarrollar aplicaciones Windows Phone, y acceder a los detalles de nuestra cuenta.

Allí debemos registrar a nuestra cuenta y a la subsección Phones.

Si nos fijamos bien en esa web pone: "Maximum number of phones you can register: 3".

En caso es que yo tenía 3 terminales ya registrados y 2 de ellos anticuados, así que he eliminado dos de ellos y he vuelto a intentar ejecutar la herramienta de desbloqueo Windows Phone Developer Registration.

Ahora sí, el terminal se ha desbloqueado perfectamente.

Y si nos fijamos en la sección anterior, veremos que nuestro terminal se ha registrado correctamente.

De hecho, podemos fijarnos en otra columna de datos de esa sección que indica si ha expirado la fecha de desbloqueo o no, para reiniciar el proceso de desbloqueo en ese terminal (en mi caso tengo ya un terminal con fecha expirada tal y como se puede observar).


Espero que todo esto le ayude a alguien que se encuentre con estos problemas o problemas parecidos.

Publicado por Jorge Serrano | con no comments

Introducción

A los que nos gusta los juegos de coches y la Xbox, casi se nos hace indispensable disponer de un mando que nos haga vivir con mayor realismo todo lo que acontece en esos juegos.

Una buena forma de lograr ese realismo sin llegar a unas cotas excesivamente frikis, es adquiriendo un volante.

La entrada de hoy es un poco friky, y trata sobre una experiencia personal y como lo he solucionado por si a alguien más le pasa y no sabe o no se atreve a hacer lo que yo he hecho.

 

Tipos de volantes

Dentro del amplio abanico de volantes que hay en el mercado para las consolas Xbox, hay algunos modelos que poseen force feedback y otros no. Mi consejo es que para tener una sensación más realista en la conducción, vayas a por un volante con force feedback. Notarás la diferencia.

Y dentro del mercado de volantes (los que tienen force feedback y los que no), los hay desde aproximadamente unos 60 € hasta los nada menos que 600 € dependiendo del acabado y calidad, y todo esto, sin contar con los asientos, soportes y pantallas donde nos tendríamos que rascar del bolsillo desde 1200 € sólo en asiento y soportes, hasta arriba sumando a esa cantidad las televisiones o monitores aparte.

Pero si tienes dinero pero no sabes por donde empezar, no te preocupes,… lo tienes fácil con este configurador que te facilitará la tarea de elegir todo lo que quieras.

Pero para los que no estamos sobrados de dinero y soñamos con una lotería para lograr ese sueño, debemos ser más modestos, como el ya desaparecido HRT F1 Team y buscar piezas de segunda mano y dejarlas lo más vistosas posibles para que hagan su función de entretenimiento.

Así que puesto que la primera premisa no la cumplo (el dinero), tendré que buscar algo más adecuado a mi economía.

 

El volante que he decidido comprar

Para ello, hay en el mercado un tipo de volante muy perseguido por su calidad/precio. Hablo del volante oficial de Microsoft (el que indico en la portada de esta entrada y que se llama Microsoft Xbox 360 Wireless Racing Wheel),… sin embargo, ese volante fue descatalogado por Microsoft y su fabricación es inexistente (tanta imitación de tableta y similar y ¿porqué los chinos no se han puesto con esto?).

He buscado y buscado, y está o agotado en todos los sitios y sin espera de stock por parte del fabricante, o a unos precios tan prohibitivos que casi me sale mejor pedir un crédito al banco (si me lo diera) y optar por la solución cara que exponía anteriormente.

Desconozco porqué Microsoft decidió no seguir con la fabricación de ese volante. Quizás quisiera publicitar únicamente la Xbox entre los amantes de los juegos de conducción y el volante no saliera rentable, pero son/somos muchos los que lo hubiéramos comprado nuevo hoy.

Como ese no es el caso y es imposible comprarlo nuevo, siempre hay un sitio en el que buscar… y no, no es ningún estercolero o basurero, sino el mercado de segunda mano donde los precios rondan entre los 75 € y los 120 € en España, hasta por 400 € fuera de España (en eBay por ejemplo).

Personalmente considero un precio de 100 € caro, así que ya no digo nada con respecto a los 120 €, mientras que el precio entre 75 € y 90 € lo considero un precio justo, aceptable y acorde al mercado con respecto a un producto obsoleto ya.

Sé que este volante llegó a costar algo más de 200 € en su tiempo, pero han pasado 4 años y ya no vale eso, y menos con el uso que algunas personas les da a los volantes.

 

Mi volante

En mi caso, me han ofrecido el volante por 120 € (no me ha interesado a ese precio), y más barato que esa cantidad. Al final he obtenido uno que me ha parecido tener un precio razonable dentro del baremo normal.

Sin embargo, este tipo de hardware tiene un problema. Su uso. O mejor dicho, el uso que le haya dado el dueño.

El que he comprado tiene el volante en bastante buenas condiciones.

El soporte que acopla el volante a la mesa también estaba en buenas condiciones.

Pero la pedalera… bueno, en realidad el plástico que recubre alrededor a los pedales, estaba arañado e incluso manchado de rotulador rojo y negro.

Entiendo como normal que la gente que acostumbra a vender las cosas de segunda mano, le da un lavado global o superficial al producto para que la entrega esté vistosa, pero en mi caso, me llegó que daba pena verlo. Quizás sea muy exigente, pero realmente no era lo que me esperaba porque denota poca seriedad por parte del vendedor.

Estuve a punto de devolverlo pero decidí quedármelo.

Sin embargo, ni el volante ni el soporte ni los pedales, tenían el aspecto estético que me gustaría que tuviera, así que me puse a limpiarlo de pegotes de pintura, polvo y suciedad típica de haberlo tenido en un trastero, descuidado o haber soportado las inclemencias de una obra.

Lamentablemente no hice fotos del estado inicial, pero tengo testigos que pueden corroborar lo que comento.

 

Limpieza

Lo primero que hice fue limpiar el volante, los cables, el soporte que une el volante a la mesa y los pedales.

Para ello, hice una visita al chino del barrio y por 6,5 € adquirí todo esto:

El contenido es muy simple:

  • Un bote de alcohol.
  • Algodones.
  • Toallitas de bebé.
  • Protectores adhesivos para la base de los pedales a la hora de ponerlo al suelo (faltaban dos de los cinco que tiene de fábrica).
  • Pintura blanca para plásticos.

Para esta primera fase, utilicé todo menos los protectores adhesivos y la pintura.

Lo que hice fue limpiar todas el hardware de modo que quedara lo más limpio posible, quitando restos de pintura, rotulador y algún que otro resto de suciedad.

Una vez finalizado todo el proceso, todo el hardware quedó bastante limpio y saneado.

La primera fase la repetí unas cuantas veces.

 

Fase de pintado

En la fase de pintado me he decantado por la utilización de un spray de color blanco mate, en esmalte sintético y con código de color 9010.

Mi bote de pintura lo podéis encontrar en esta web.

Y más concretamente aquí.

El objetivo, pintar el borde blanco que recubre a los pedales que es la parte que estaba arañada del uso.

Para llevar acabo esta tarea, he puesto cinta adhesiva en la zona gris de los pedales y he cubierto los pedales para que a la hora de pintar con el spray no se pinten de blanco claro está.

Después de una primera mano de pintura, el aspecto de esta parte era este:

Sin embargo, le he dado hasta 4 manos de pintura con el spray con el fin de que la pintura refuerce más su acoplamiento a la base de plástico.

 

Fase de fijación

Sin embargo, el proceso no finaliza con la fase de pintado, así que se requiere dar el punto definitivo de fijación, algo que he dado con un spray de barniz acrílico satinado que me ha costado 2,5 € más.

En concreto, el que he usado es este:

Se trata de un barniz satinado con código S199 que sino estoy equivocado, es el que equivale a este en la web del fabricante.

Después de repetir la operación de barnizado sobre la superficie de dos a tres veces, el resultado es este:

Realmente se aprecia poco en la imagen y aprecia mucho mejor en la realidad.

 

El resultado final

De hecho, uno de los errores que se tienen a la hora de comprar este tipo de volantes (lo aviso para que a otros no les pase), es que las fotos que te envían los vendedores respecto a este producto engañan con respecto a la realidad, y una cosa es la imagen que te envían y otra la de verdad, la que ves tú con tus propios ojos que es cuando ves lo detalles.

El vendedor no me envió ninguna foto trucada, pero lógicamente no se apreciaban bien los detalles del poco cuidado que se tuvo y el flashazo no ayuda a detectar esos detalles (fallo mío).

Tanto es así, que la imagen que me envió el vendedor de los pedales era esta:

Y ahí no se muestran ni las manchas ni churretes que tenía, ni los pintarrajos rojos y negros, ni los arañazos. A simple vista parece que estaba todo ok, pero no era así (volvedme a llamar meticuloso).

Pero nada que dos o tres pasadas de algodón con alcohol y toallitas de bebé no quiten, pero claro… siempre te llevas un poco de decepción por no haber recibido toda la información sobre el estado del producto.

El caso es que ese es el antes, y aquí va el después de todo el proceso de limpiado y fijación:

Como se puede apreciar, el aspecto es mucho más vistoso.

Un detalle principal del logo de Xbox 360 para que se vea algo de detalle del proceso finalizado:

 

Mejoras

Sin embargo, creo que el proceso puede mejorarse.

En mi caso no soy ningún experto en todo esto, y alguna motita de polvo se ha alojado a la pintura.

La idea es hacer esto en un lugar seco y cerrado, pero yo lo he hecho en un lugar abierto y con viento, así que reconozco que no lo he hecho en las mejores condiciones. Aún y así, no lo quiero para ninguna exposición, y seguramente ensucie el soporte una vez apoye sobre él mis pezuñas.

El resultado no obstante ha sido más que satisfactorio, sin embargo, la base de barniz que le he aplicado no me termina de convencer, y si dejo el dedo apretado unos segundos se marca un poco la huella dactilar con el efecto de la presión y el calor del dedo. Como estoy escribiendo esta entrada a las pocas horas de haber finalizado el proceso, es posible que le falte reposo o bien que necesite un tipo de barniz diferente.

No obstante, la huella dactilar la he quitado fácilmente con un algodón humedecido muy muy poco en alcohol, pero sigo pensando en que el proceso necesita una mejora o simplemente tiempo. Eso lo veré en los próximos días.

Espero que le sirva a alguien mi experiencia.

Publicado por Jorge Serrano | 2 comment(s)
Archivado en:

Introducción

A la hora de diseñar nuestras aplicaciones en Windows 8, es posible que nos encontremos con la necesidad de preparar una maqueta de estilos y formas respecto a nuestra aplicación. Lo que vulgarmente se denomina prototipo (en su fase inicial).

Como todos sabemos, lo ideal es hacer un fake, pero muchas veces y para ganar tiempo, es preciso hacer o preparar unos wireframes o prototipos que compartiremos con nuestro equipo de trabajo (desarrollo + UX).

Sin embargo, en muchas ocasiones se nos pide incluso más flexibilidad y menos tiempo para hacer o preparar grandes florituras, es decir,… hacernos una idea rápida de como va a ser nuestra aplicación.

¿Cómo salir adelante cuando los plazos aprietan, y se pide flexibilidad y rapidez en la toma de decisiones?.

 

Wireframe templates para PowerPoint

Sí, no me he vuelto loco.

Si se nos pide flexibilidad y rapidez a la hora de discutir con el cliente o con el equipo como podría ser nuestra aplicación Windows 8, no lo dudemos… hacerlo con el Notepad quedará más cool, pero nos llevará mucho más trabajo, y hacerlo con Visio y PowerPoint nos quedará muy vistoso, no será tan friky pero nos llevará mucho menos tiempo.

En este caso, vamos a utilizar PowerPoint, y para ello, unas plantillas gratuitas que generosamente nos ofrece Andreas Wulf y Austin Andrews.

Estas plantillas las podrás encontrar en este enlace.

 

Espero que sean de utilidad.

Publicado por Jorge Serrano | con no comments
Archivado en:

Introducción

Cuando deseamos migrar una base de datos de SQL Server a SQL Azure, experimentaremos diferentes fases de sentimientos encontrados, y es que pasar estructuras de tablas, relaciones, datos maestros y otras partes, desde una base de datos SQL Server a SQL Azure no es tarea fácil.

Sin embargo, tenemos una herramienta que nos va a facilitar enormemente las cosas para que esa transición y esa carga sea lo menos pesada posible y sí lo más liviana y ligera posible.

Esta herramienta es SQL Database MW o SQL Database Migration Wizard si se desea emplear el nombre largo de la misma.

 

¿Qué es SQL Database MW?

Esta herramienta gratuita nos facilitará la tarea de migrar bases de datos en SQL Server 2005, 2008 y 2012 a SQL Azure.

Existen dos versiones:

SQL Database Migration Wizard v3.x.x que requiere SQL Server 2008 R2 SP1.

SQL Database Migration Wizard v4.x.x que requiere SQL Server 2012.

 

¿Dónde localizar SQL Database MW?

Esta herramienta la podemos localizar en codeplex.

 

Ejecutando la herramienta

Lo primero que tenemos que hacer, es descargar los binarios de la herramienta y descomprimir los archivos de la misma en una carpeta.

Una vez hecho esto, ejecutaremos la aplicación (en mi caso, la versión 3.9.9.1 y el fichero SQLAzureMW.exe).

La aplicación se mostrará en una ventana similar a la siguiente:

En nuestro caso, voy a migrar una tabla con datos de SQL Server a SQL Azure para lo cual, seleccionaré la opción de Analyze/Migrate y en concreto, la primera opción Database.

A continuación, pulsaremos el botón Next.

Una vez hecho esto, aparecerá una ventana para establecer la conexión con la fuente origen de datos.

Seleccionaremos el servidor y las características de conexión correspondientes.

Como se puede apreciar, adicionalmente he decidido indicarle a la herramienta, que me muestre todas las bases de datos de dicha conexión para indicarle la que quiero migrar.

Otra opción es seleccionar la opción Specify Database para indicarle el nombre concreto de la base de datos, pero la opción Master DB es la opción más cómoda.

Estableceremos la conexión pulsando el botón Connect y aparecerá una nueva ventana con el listado de todas las bases de datos.

Seleccionaremos la que queremos migrar.

Pulsaremos el botón Next para continuar.

Aparecerá una nueva ventana que nos permitirá seleccionar las partes de objetos de SQL Server que queremos migrar.

En principio y para mi prueba, he decidido seleccionar todos los objetos.

Una vez resuelto este punto, volveremos a pulsar el botón Next.

Aparecerá entonces, una nueva ventana con un resumen de los objetos seleccionados anteriormente.

Una vez más, pulsaremos el botón Next.

Aparecerá una ventana de diálogo que nos preguntará si deseamos crear el script o no.

Pulsamos afirmativamente y la herramienta empezará a preparar el script por nosotros.

Una vez finalice el proceso, podremos revisar el informe de generación del script y el script en sí.

Si queremos, podemos guardar esta información o pasar de ella como voy a hacer yo en esta demostración.

Como todo el rato hasta ahora, volveremos a pulsar el botón Next.

En este momento, seleccionaremos la conexión destino con nuestra base de datos SQL Azure y estableceremos la conexión correspondiente al igual que hicimos para el origen de datos en SQL Server.

Una vez que hemos indicado los datos de conexión con SQL Azure correspondientes, haremos clic en el botón Connect.

Si todo ha ido tal y como se espera, la aplicación nos mostrará un listado de las bases de datos de SQL Azure.

La base de datos ya la tengo creada y lo que voy a hacer es pasar las tablas de SQL Server a SQL Azure, así como sus datos, etc.

Por lo tanto, una vez seleccionada la base de datos del listado anterior, haremos clic en el botón Next.

Aparecerá una ventana de notificación preguntándonos si queremos ejecutar el script contra el servidor de SQL destino (nuestro SQL Azure), a lo que responderemos afirmativamente.

El proceso de migración dará comienzo y se empezarán a pasar datos.

Si todo va bien, el proceso finalizará sin ningún error después de unos minutos.

Ya solamente tenemos que hacer clic en el botón Exit para cerrar la aplicación.

Como vemos, se trata de una herramienta muy sencilla de utilizar y que nos ahorra mucho tiempo y muchos pasos, asegurándonos un proceso rápido, seguro y limpio.

Si ahora abrimos SQL Server Management Studio por ejemplo e indicamos los parámetros de conexión (servidor, usuario y contraseña), podremos probar que los datos han sido migrados correctamente y todo está según lo esperado.

Publicado por Jorge Serrano | con no comments
Archivado en:

Introducción

El hecho de que me haya animado a escribir esta entrada, es debido fundamentalmente a que en dos días prácticamente seguidos, he tenido la oportunidad de charlar con dos compañeros distintos de trabajo sobre un tema concurrente en el tiempo:

La fidelidad de los clientes en las compañías en las que consumen bienes y servicios y lo que estas aportan a los clientes fieles.


Poniéndonos en situación

Creo que de todos es sabido (y sino ya lo sabes a partir de ahora), que una de las primeras premisas que te explican en marketing es que hacer un cliente cuesta mucho esfuerzo y dinero, y perderlo muy muy poco.
Sin embargo, cuando pierdes un cliente por insatisfacción, engaño o molestia, en un porcentaje que se acerca al 100%, ese cliente lo habrás perdido para siempre salvo contadas, raras y excepcionales ocasiones en las que regresa a ti nuevamente.
Una de esas situaciones extraordinarias en las que un cliente insatisfecho regresa es que la competencia a la que se haya ido sea la única existente en el mercado, e incluso peor que la empresa de la que se fue, algo que por desgracia ocurre en no pocas ocasiones.

Un baremo que se estudia mucho en marketing para tomar el pulso de los clientes son los resultados del llamado análisis de satisfacción del cliente.
Se trata de un baremo bastante útil, sí, pero muchas empresas lo miran por encima o no lo analizan con mayor profundidad y no entienden que dentro de la satisfacción del cliente existen varios niveles diferentes, siendo el más alto el de la satisfacción completa del cliente, un valor muy difícil de alcanzar realmente, ya que estamos hablando de la excelencia, algo a lo que se debería tender como meta única.
Es precisamente en esa amplia horquilla en la que se mueve la satisfacción del cliente a la que no se le presta siempre la misma atención y sobre la que muchos clientes deciden cambiar de empresa o compañía.

Pero esto no es extrapolable solamente al consumo, también ocurre algo parecido con los propios empleados de una empresa y por eso muchos de ellos terminan cambiando de empleo.


Objetivos de una empresa

Regresando al tema principal que nos ocupa, una empresa no es una ONG y se nutre de balances económicos, beneficios, pérdidas, inversiones, etc, por lo que cada vez que hablamos de satisfacción del cliente, debemos tener en cuenta dos vías fundamentales para aportar esos valores positivos a la compañía.

Una primera vía estaría formada por la consecución de nuevos clientes. Esto se consigue de muy diferentes maneras.
Como dije antes, conseguir un nuevo cliente suele costar tiempo y dinero, pero algo que se obvia y que es fundamental igualmente es el boca a boca. Pero para todo ello, la imagen actual de marca y empresa es vital.
La imagen de marca y la percepción de los potenciales consumidores se puede lograr a base de esfuerzos como por ejemplo el establecimiento de canales de comunicación adecuados y más efectivos, la mejora de la red de ventas, el posicionamiento de la marca, etc.

Una segunda vía estaría formada por los clientes y consumidores actuales de la marca.
Es indudable que un cliente actual es el que está consumiendo nuestros productos, por lo que esa incógnita la podemos despejar centrándonos únicamente en la incógnita de lograr vender a ese cliente más productos.
Sin embargo, si un cliente actual no está completamente satisfecho y tratamos de venderle un producto, se puede producir un efecto contrario de rechazo decidiendo en ese mismo momento, cancelar nuestra relación.

En todo caso, una empresa debe tener siempre presente que haga lo que haga va a perder clientes, porque nunca puedes satisfacer todas las demandas.
El éxito para una empresa es tener un ratio menor del 2% de pérdida de clientes. De esta manera, un 5% por ejemplo es normalmente una cantidad bastante grande de pérdidas y denotan un problema a medio plazo.


Objetivos de un cliente

Un cliente por su parte puede ser de diferentes tipos.

Existen los clientes que consumen un producto y no vuelven a tener contacto con la marca más veces..., o si la vuelven a tener es después de muchísimo tiempo para repetir la operación. Son los clientes Guadiana.

También tenemos a los clientes que después de consumir un producto y quedar satisfechos, vuelven a repetir la operación, o que incluso estando satisfechos y sin ánimo de consumir al menos de momento más que lo que ha consumido o tiene contratado, son tentados por la competencia y no tienen ninguna intención de cambiar porque están vinculados sentimental o de alguna otra manera con la compañía, marca, etc.

En tercer lugar tenemos a los clientes insatisfechos que continúan consumiendo servicios o productos, más por inercia que por otra causa especial. Son clientes denominados residuales.

Finalmente, tenemos también a los clientes que en un estado insatisfecho han decidido cambiar de empresa.


Y aquí estamos...

Y después de todo lo comentado anteriormente (y me he ahorrado muchos detalles para no parecer esto una clase de marketing), viene la realidad. Al menos en España.

Pregunta directa.
¿Porqué las empresas consideran o priorizan la contratación de nuevos clientes en lugar de potenciar la satisfacción del actual cliente?.

Y es que también es sabido que cuando un cliente consume un producto, se da por hecho que salvo que la caguemos, raramente va a cambiar y se va a ir con la competencia (¡error!).
También es frecuente el hecho de que muchas empresas se centren en hacer cartera de clientes y meterlos en su CRM para enseñarles a los inversores cuantos clientes se han hecho, eso sí... a costa de gastar mucho dinero... perdón... a costa de tirar el dinero quería decir (¡error!).
También es un mito pensar que el cliente lo será para toda la vida... (¡error y de los gordos!).

Vivimos en un mundo globalizado, y por lo tanto, cada vez el consumidor posee mayores oportunidades. Un ejemplo de esto son las ventas por Internet. Hay productos como la luz, el agua o el teléfono que hoy día no se pueden consumir por Internet, pero existen otros productos que sí.

Pero pongamos ejemplos reales a todo esto.

El ejemplo más típico de todo lo comentado anteriormente lo tenemos con las empresas de telecomunicaciones en España.
Desde la liberalización de las telecomunicaciones en el año 1998, el marco comercial apenas ha cambiado.
Este año 2013 se prevé la liberalización de la energía principalmente y veremos que ocurre, pero mucho me temo que copiarán el mismo marco o modelo comercial de agresividad en el que se ha movido el de las telecomunicaciones y en el que lo más importante es hacer clientes, y cuantos más mejor, sin importar cuantos clientes actuales se pierden, así que los clientes estarán saltando de una compañía a otra como si estuviéramos salteando guisantes en una sartén.

En telecomunicaciones hoy día, un cliente de toda la vida de una operadora recibe menos beneficios que un cliente que decide hacer la portabilidad. Incluso ha habido personas que han estado pegando saltos de portabilidad en portabilidad en busca no de la mejor oferta, sino de sacar terminales de última generación al mejor precio (aka gratis).
Las empresas de telecomunicaciones que estaban ávidas por hacer clientes, entraban en esa dinámica porque comercial o estratégicamente las interesaba, y así hemos estado en estos últimos casi 15 años.

Como ejemplo me citaré a mí mismo que estando en Telefónica (Movistar) desde hace creo recordar algo más de 15 años ya (que tiempos aquellos del Moviline), no he recibido NUNCA ninguna oferta o regalo de un terminal de última generación.
Sin embargo, si siendo cliente Movistar me voy a otra operadora y elijo la portabilidad, esa operadora sí me regala ese terminal que añoro tener si le prometo fidelidad durante 12, 18 ó 24 meses.
Es decir, me presta mayor atención y mimos una nueva compañía con la que nunca he hecho tratos que mi compañía de toda la vida. ¿Curioso?.

Y es que muchas compañías se olvidan de una cosa.
La primera y más importante es que un cliente es MÁS IMPORTANTE que un futuro cliente, y que un cliente contento y satisfecho es un potencial escaparate para animar a otros amigos o conocidos a entrar a formar parte del grupo de consumidores de una empresa.
¿Qué creen que comentaré en una reunión informal cuando uno de mis amigos enseñe todo ilusionado y contento el nuevo terminal que ha obtenido gracias a la portabilidad que ha realizado desde el operador A al operador B?.
Pues simple y llano... "En Movistar son unos ratas".
A lo que otro amigo me dirá... "En Vodafone estamos igual".
Y otro dirá... "En Amena no somos distintos".
Y finalmente otro más dirá... "¡Anda!, ¿y qué os creéis que pasa en Yoigo?".
Vamos... que sólo te queda una alternativa... hacer como tu amigo y portar tu número a otra compañía y dejar la compañía telefónica de toda la vida.

Otro ejemplo.
Una empresa que tiene seguros médicos y que siendo cliente de ellos desde hace años, te invitan a salirte de la compañía y cancelar el seguro para volver a contratarlo y poder así aprovechar una de las ofertas de promoción que tienen para... ¡¡¡NUEVOS CLIENTES!!!.
Vamos... que le importa un rábano que seas cliente actual de la compañía, porque lo que quieren comercialmente es tener un contador que sume un +1 a "nuevos clientes", aunque sea a costa de poner un -1 a clientes actuales, porque el inversor de turno no va a ver, prestar atención o contabilizar esos datos.

Estos ejemplos los quiero compartir porque además de ser reales, dejan a las claras una triste afirmación.

Un cliente nuevo es mejor valorado que un cliente antiguo y fiel a la marca, cuando en realidad debería ser al contrario.

Ahora voy a poner un ejemplo teórico de actuación por parte de una empresa de telecomunicaciones que quiere romper el mercado preparando un modelo comercial moderno y diferente.

Si por ejemplo, un cliente fiel recibe una prebenda cada... ¿4 años por ejemplo?, ¿creéis que ese cliente va a cambiarse de compañía?.
Pongo un ejemplo más descriptivo aún.
Si hoy sale Windows Phone 8 y soy un fanático de dichos terminales y el operador de telecomunicaciones decide ofrecerme gratis un Nokia 820 con una permanencia de 24 meses y un Nokia 920 con una permanencia de 36 meses con consumo fijo, etc... ¿creéis realmente que aceptaré o rechazaré la oferta?.
Imaginad lo mismo para otros terminales tipo iPhone, Android, BlackBerry, etc...

Ahora pensad que llego a esos 24 meses de permanencia por ejemplo y mi Nokia 820 se me queda obsoleto o simplemente me he cansado de él... ¿que haría el consumidor?.
Seguramente cambiar, pero a lo mejor puede acogerse a un servicio como los actuales puntos que tienen las operadoras para obtener una rebaja.
Pero imaginemos nuevamente que el cliente está contento con el terminal y decide continuar usándolo otros 24 meses más (4 años ya), y el operador me llama sin yo decirle nada para decirme que han detectado que llevo 4 años usando el mismo terminal que me ofrecieron y que ahora me ofrece otro terminal nuevo modelo gratis si le ofrezco fidelidad nuevamente... ¿que creéis que pasaría?.

¿Y qué creéis que pasaría cuando me juntara con los otros colegas de profesión, amigos y familia como hice antes para hablar estas cosas?.
Indudablemente les diría que utilizaran los servicios de mi operador de telecomunicaciones porque las ventajas son enormes, me cuidan, etc.
¿Y qué creéis que la portabilidad les sale gratis a las compañías de telecomunicaciones?. Pues no, da mucho dinero... de ahí que estén jugando con este modelo de negocio sin pensar que es el chocolate del loro y que otros modelos les aporta mayores beneficios.

¿Y que hay aquí en esta forma de actuar diferente realmente?. Pues varias cosas.

Por un lado, se crea una dependencia y una estrecha relación casi personalizada entre empresa y cliente, y entre cliente y empresa.
La fidelidad va en doble dirección y no sólo como hasta ahora ocurre casi siempre, en la que es el cliente el que le puede ser fiel o no a la empresa.
La satisfacción del cliente aumenta.
La empresa además recoge como canal indirecto una entrada de clientes debido a las recomendaciones y satisfacciones de los actuales clientes.
El cliente se encuentra mimado y valorado.
El cliente no se planteará ningún cambio si su grado de satisfacción y servicio son óptimos.
La empresa recogerá unos ingresos fijos de acuerdo al contrato de fidelidad establecido, por lo que podrá incluso hacer estudios de inversión y contabilidad más precisos.

Me gustaría poner dos ejemplos o anécdotas más que han salido a colación de comentar todo esto con algunos de mis compañeros de trabajo.

Mi primera impresora fue una HP Deskjet 510 en blanco y negro.
Me acuerdo perfectamente.
Yo era un ignorante de todo el mundillo informático y alguien me dijo que era muy bueno registrar los productos por el soporte de las empresas.
Como era eso, un ignorante... se me ocurrió registrar en HP mi impresora enviando el formulario de registro a una dirección de USA.
Lo hice y me olvidé de aquello... total... ¿para qué servirá?.
De hecho, algunos conocidos me dijeron cuando lo comenté que había perdido el dinero de los sellos y que no serviría para nada...
Comencé mis estudios de informática y de repente viene un paquete a casa desde USA.
Cuando lo abrí me encontré un aparato metálico y pesado y una carta.
La carta pedía disculpas por un fallo en la impresora e indicaba que como usuario y consumidor de dicha impresora, me enviaban dicho aparato para resolver los problemas detectados.
El problema era muy simple. Cuando la bandeja de papel llegaba a tener como tres o cuatro hojas, la impresora no las enganchaba.
El aparatoso soporte que me enviaban levantaba un poco las hojas para que los rodillos las pillara. Así de simple.
Lo cierto es que sí había notado el fallo, pero lo solventaba añadiendo más papel.
La verdad es que aquello hizo que recomendara la marca a todos mis conocidos.

Años después, adquirí un Citröen C5.
Era un anti-citröen, no lo niego, pero ya sabéis... calidad/precio... achuchado económicamente,... etc.
Lo adquirí y al poco tiempo de usarlo detecté un fallo de fábrica que remití a Francia.
Al cabo de los meses recibí una carta que me indicaba que me acercara por un taller Citröen para resolver gratuitamente algunos problemas técnicos detectados en el modelo.
Cuando fui al taller y pregunté, me dijeron que las reparaciones eran de unos 1000 € por coche y que estaban llamados a hacerlas todos los modelos desde una fecha determinada.
Que no eran fallos graves y que quien no quisiera realizar las reparaciones podía circular sin problemas, pero que lógicamente me recomendaban hacerlas, a lo que accedí como es lógico.
Después de utilizar el vehículo durante algo más de 8 años y de aquella anécdota... os lo podéis imaginar... me compré otro Citröen C5.

Todo esto lo comento porque me duele enormemente ver como las empresas invierten (o tiran) una gran cantidad de dinero en hacer nuevos clientes ignorando a los que ya tiene, invitándoles prácticamente a ser clientes residuales o incluso a cambiar de marca, compañía, empresa, etc.

Y es que creo que es más importante mantener a tus actuales clientes y potenciar esa relación empresa-cliente, cliente-empresa, que pensar únicamente en crear nuevos clientes.
Nuestras ansias de crecer a veces, nos hace perder el foco de lo que importa,... y cuidado, que hay quienes se mueren de éxito.

¿Tienes alguna fórmula para defender el marco normal de actuación de las empresas para olvidar a los clientes actuales y fieles y atender mejor a los potenciales nuevos clientes?. ¿Qué opinas?.

Publicado por Jorge Serrano | 5 comment(s)
Archivado en:

Introducción

La semana pasada, mi compañero de trabajo y sufrimientos, Luis Ruiz Pavón, escribió una interesantísima entrada sobre cómo utilizar LINQPad 4 y NHibernate para probar consultas LINQ y resolver posibles problemas de rendimiento, cuellos de botella, etc., sin tener que hacer grandes alardes de programación… es decir, sin utilizar Visual Studio.

En mi caso, voy a preparar una entrada variante y complementaria de la de Luis pero enfocándome en lo que sería un pequeño ejemplo paso a paso de cómo llevar a cabo esta tarea utilizando levemente Visual Studio para aquellos que se encuentren un poco perdidos en la utilización de LINQPad 4 y NHibernate Profiler tal y como apuntaba Luis.

 

Preparando el modelo

Lo primero de todo, vamos a crear un proyecto de tipo Class Library en C# por ejemplo, al que le he puesto el nombre de NHibernateTest y en el que agregaremos una clase de nombre Exployee y con los siguientes campos:

   1:  namespace NHibernateTest
   2:  {
   3:   
   4:      using System;
   5:   
   6:      
   7:      public class Employee
   8:      {
   9:   
  10:          public virtual Guid Id { get; set; }
  11:          public virtual string Name { get; set; }
  12:          public virtual string Surname { get; set; }
  13:          public virtual string Address { get; set; }
  14:          public virtual string City { get; set; }
  15:          public virtual string Country { get; set; }
  16:   
  17:      } // Employee
  18:   
  19:  } // NHibernateTest

A continuación, compilaremos nuestro proyecto para ver que todo está bien.

Una vez hecho esto, nos olvidaremos ya de Visual Studio.

Pensemos por lo tanto, en que hemos preparado un proyecto con los objetos de dominio o similar.

Sin embargo, nos gustaría poder “jugar” con ellos introduciendo datos o haciendo algunas operaciones básicas o genéricas con NHibernate.

Crear un proyecto de consola o similar es una alternativa, pero nos obligaría a abrir Visual Studio y trastear, cuando en realidad, lo que queremos, es hacer algo más ágil, rápido y sencillo.

 

Preparando LINQPad 4

Vamos a ejecutar por lo tanto LINQPad 4.

Lo primero que haremos será modificar la propiedad Language a C# Statements.

Una vez hecho esto, si queremos, podemos establecer una conexión con nuestra base de datos.

En concreto, tengo una base de datos en SQL SERVER a la que le he puesto el nombre de TESTS, y que tiene una tabla de nombre Employees con los campos indicados en la clase de C# que vimos anteriormente:

Sólo de modo opcional y si quisiéramos establecer una conexión en LINQPad 4 con nuestra fuente de datos, haríamos clic en la opción Add connection de la aplicación:

Probaríamos la conexión y veremos que todo es correcto. Pero en este caso, este último paso lo vamos a obviar.

 

Fichero de configuración de NHibernate en lugar de utilizar la conexión con LINQPad 4

En mi caso sin embargo, voy a tirar de ficheros de configuración.

Así que para establecer la conexión con nuestra fuente de datos, voy a crear un archivo de configuración llamado sqlserver.hibernate.cfg.xml dentro del cual he agregado la siguiente configuración:

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <configuration>
   3:    <configSections>
   4:      <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/>
   5:    </configSections>
   6:    <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
   7:      <session-factory>
   8:        <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
   9:        <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
  10:        <property name="connection.connection_string">Data Source=P-JOSE8\MSSQLSERVER2012;
  11:        Initial Catalog=TESTS;Integrated Security=True</property>
  12:      </session-factory>
  13:    </hibernate-configuration>
  14:  </configuration>

Recapitulando, hemos dejado preparado LINQPad 4 y hemos creado una biblioteca de clases en Visual Studio donde hemos creado nuestra clase Employee con sus campos.

Tenemos una base de datos de prueba con una tabla Employees con los campos correspondientes, y por último, hemos creado un archivo de configuración de NHibernate para establecer la conexión con nuestra fuente de datos.

 

Creando el archivo de mapeo con la entidad Employee

El siguiente paso será el de preparar el archivo de mapeo de nuestra entidad Employee para que NHibernate interprete correctamente sus campos y pueda trabajar con ella sin problemas.

Existen otras formas de llevar a cabo esto, pero aquí y para probar todo, vamos a hacerlo así.

El archivo de mapeo se llamará Employee.hbm.xml, y su contenido queda de la siguiente manera:

 

   1:  <?xml version="1.0" encoding="utf-8" ?>
   2:  <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
   3:  assembly="NHibernateTest"
   4:  namespace="NHibernateTest">
   5:    <class name="Employee" table="Employees">
   6:      <id name="Id">
   7:        <generator class="guid.comb" />
   8:      </id>
   9:      <property name="Name" not-null="true" />
  10:      <property name="Surname" />
  11:      <property name="Address" />
  12:      <property name="City" />
  13:      <property name="Country" />
  14:    </class>
  15:  </hibernate-mapping>

Vuelta a LINQPad 4, agregando ensamblados y namespaces

Para completar todo el proceso, vamos a agregar algunos ensamblados y namespaces a LINQPad 4 para que cuando agreguemos el código de ejecución, pueda localizar e interpretar las instrucciones de código que vamos a ejecutar de forma correcta.

Lo primero que debemos tener en la herramienta NHibernate Profiler que nos va a permitir analizar las instrucciones que lanzamos contra NHibernate.

Por otro lado, en LINQPad 4 vamos a pulsar la tecla F4 que nos permite abrir la ventana para agregar referencias, ensamblados y namespaces.

Nos situaremos en la solapa Additional References.

Los ensamblados a agregar son estos cuatro:

  • HibernatingRhinos.Profiler.Appender.dll
  • Iesi.Collections.dll
  • NHibernate.dll
  • NHibernateTest.dll

Dentro de la carpeta en la que tenemos nuestra herramienta de profiling encontraremos un ensamblado de nombre HibernatingRhinos.Profiler.Appender.dll que deberemos agregar en las referencias adicionales de LINQPad 4.

También deberemos agregar las librerías Iesi.Collections.dll y NHibernate.dll que encontraremos en la carpeta de ensamblados de NHibernate.

Y finalmente agregaremos el ensamblado que creamos con Visual Studio al principio del todo.

Para concluir, iremos a la solapa Additional Namespace Imports y agregaremos tres namespaces:

  • NHibernate
  • NHibernate.Cfg
  • NHibernateTest

Bastará con poner cada uno de los nombres de los namespaces ahí uno debajo del anterior.

LINQPad 4 ya se encargará de hacer el correspondiente using por nosotros.

 

Escribiendo el código a ejecutar en LINQPad 4

Ya estamos prácticamente concluyendo.

El último paso es escribir nuestro código y ejecutarlo.

Para ello, vamos a escribir el siguiente código:

   1:  HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize();
   2:   
   3:  ISessionFactory sessionFactory = new Configuration().
   4:  Configure(@"C:\Temp\sqlserver.hibernate.cfg.xml").
   5:  AddFile(@"C:\Temp\Employee.hbm.xml").BuildSessionFactory();
   6:      using (ISession session = sessionFactory.OpenSession())
   7:      {
   8:          using (ITransaction transaction = session.BeginTransaction())
   9:          {
  10:              Employee employee = new Employee();
  11:              employee.Name = "Pedrito";
  12:              employee.Surname = "Gómez Sánchez";
  13:              employee.Address = "Calle Mayor, 1";
  14:              employee.City = "Burgos";
  15:              employee.Country = "Spain";
  16:              session.Save(employee);
  17:              transaction.Commit();
  18:              session.Close();
  19:          }
  20:      }

Este ejemplo, cargará el archivo de configuración de NHibernate para establecer la conexión con NHibernate y el archivo de mapeo de la entidad Employee.

Finalmente agregaré un nuevo empleado a la base de datos con los datos que hemos agregado aquí.

Podríamos haber hecho un bucle para agregar un conjunto de empleados a modo de ejemplo o cualquier otra cosa, pero sirva este ejemplo para mostrar cómo escribir datos en una tabla utilizando NHibernate y sin apenas utilizar Visual Studio.

El caso es que para ejecutar nuestro código, bastará con pulsar el botón de ejecución o pulsar la tecla F5.

Si la ejecución es correcta, veremos un mensaje en la parte inferior de la aplicación LINQPad 4 que indica algo así como Query successful.

 

Analizando NHibernate Profiler

Adicionalmente y con ayuda del profiler, podemos obtener información valiosa a la hora de ejecutar nuestras instrucciones.

Si comprobamos los datos en SQL Server, veremos que estos están correctamente persistidos.

(Nota: también podemos ver los datos persistidos desde LINQPad 4 si hemos establecido previamente una conexión con el modelo de datos como se apuntaba al principio, lo cuál nos evitará incluso la tarea de irnos a SQL Server Management Studio).

Tal y como decía Luis en su entrada, estas prácticas nos pueden ahorrar mucho tiempo y quebraderos de cabeza.

Podemos crear y ejecutar instrucciones LINQ o podemos incluso probar determinados comportamientos y ejecuciones en nuestro código sin tener la necesidad de abrir Visual Studio para ello.

Espero que le resulte de utilidad a más gente.

Introducción

Microsoft ha publicado una actualización de WCF Data Services v5.0, con el que podemos crear y consumir servicios de datos para la Web a través del protocolo OData (Open Data Protocol) versión 3.

La idea es que entre otras cosas, podamos utilizar fácilmente los verbos HTTP para poder acceder y cambiar datos.

Los requisitos de esta versión son Microsoft .NET Framework 4.0 Visual Studio 2010.

Este paquete resuelve diferentes bugs al mismo tiempo que añade mejoras.

Adicionalmente, Microsoft ha publicado igualmente una nueva versión de WCF Data Services, la versión 5.2 que añade mejoras y resuelve bugs y problemas. Esta nueva versión puede ser instalada en equipos con Microsoft .NET Framework 4.0 y Microsoft .NET Framework 4.5, así como en Visual Studio 2010 y Visual Studio 2012.

Recomendación

Microsoft recomienda encarecidamente la instalación de la actualización en el caso de que ya utilices WCF Data Services en la middle-tier, especialmente para los usuarios de LightSwitch en Visual Studio 2012.

Respecto a este último punto, recomiendo acceder a la información que sobre ello ha publicado Beth Massi.

Descarga

Podrás acceder a la descarga de la actualización de WCF Data Services v5.0 for OData V3 en este enlace (5.3 Mb).

También puedes acceder a WCF Data Services v5.2 RTM Tools Installer, que utilizaremos para actualizar los paquetes NuGet referenciados por la plantilla de WCF Data Services a la versión v5.2.0, resolviendo además, algunos bugs detectados que tiraban abajo a Visual Studio en la generación de referencias a servicios contra modelos grandes. Se puede acceder a este otro paquete en este enlace (10.4 Mb). Los requisitos mínimos de esta herramienta son Microsoft .NET Framework 4.0 ó Microsoft .NET Framework 4.5, y Visual Studio 2010 ó Visual Studio 2012.

Finalmente, agrego igualmente el enlace de NuGet de esta nueva versión 5.2 y el enlace del sitio oficial de Microsoft con la información de esta nueva versión 5.2.

Aprendizaje

Si lo que quieres es saber un poco más sobre WCF Data Services, entonces te recomiendo el siguiente tutorial.

Publicado por Jorge Serrano | con no comments
Archivado en:
Más artículos < Página anterior - Página siguiente >