Friday, September 25, 2009

My best WPF magic for Model-View-ViewModel (M-V-VM) with Routed Commands

Some time ago I had the required free time to think about a nice way to implement a set of classes and ideas that will allow me to build a WPF application that:

- Honors the Model-View-ViewModel pattern.
- Keeps the view as simple as possible, ideally as a template and no code-behind.
- Uses the power of the Command pattern in WPF (Routed Commands), keeping the View agnostic about the logic encapsulated in commands.

After some attempts, the result are 2 classes that make this all possible in a very elegant way, I think. The first class is the ViewModelBase (fragment):

public abstract class ViewModelBase
{
  // Something like the "Null object pattern"
  protected static ViewModelBase EmptyViewModel = new EmptyViewModel();

  public IEnumerable CommandBindings { get; }
  public IEnumerable InputBindings { get; }
  protected abstract void PrepareBindings();
}

The ViewModelBase class, as its name implies, is supposed to be the base class of all the ViewModels, and it is here where you define what to do when a RoutedCommand is executed. It is the glue between the RoutedCommands in the View and the command execution logic in the ViewModel.

Then, there is the ViewModelControl class (full text):

public class ViewModelControl : ContentControl
{
  protected override void OnContentChanged(object oldContent, object newContent)
  {
    CommandBindings.Clear();
    ViewModelBase viewModel = newContent as ViewModelBase;
    if (viewModel != null)
    {
      foreach (var binding in viewModel.CommandBindings)
      {
        CommandBindings.Add(binding);
      }
      InputBindings.Clear();
      foreach (var binding in viewModel.InputBindings)
      {
        InputBindings.Add(binding);
      }
    }
    base.OnContentChanged(oldContent, newContent);
  }
}

This control takes care of associating the CommandBindings to the visual elements so that the RoutedCommands mechanism works.

And that's it. There are some implementation details missing, but with these classes in place you just have to:

1- Create your ViewModel classes inheriting from ViewModelBase.
2- Provide the implementation of their PrepareBindings methods.
3- Create the templates for your ViewModels.
4- Bind your controls to the commands.

Using this implementation you'll get these results:

1- You'll have your RoutedCommands.
2- Logic for these commands will be in your ViewModel classes, where you can test it.
3- No event handlers, no code-behinds required.

Mix this with INotifyPropertyChanged in your ViewModels and DataModels and you'll have a cool architecture for your View. Here's an example:

1. Define a routed commands:

public class ViewCommands
{
  public static RoutedCommand MyRoutedCommand;
  static ViewCommands()
  {
    MyRoutedCommand = new RoutedCommand("MyRouted", typeof(ViewCommands));
  }
}


2. Define a ViewModel:

public class MyViewModel : ViewModelBase
{
  protected override void PrepareBindings()
  {
    this.AddCommandBindings(new CommandBinding(
    ViewCommands. MyRoutedCommand,
      (x, y) => DoSomethingIfMyRoutedIsExecutedOnThisViewModel(),
      (x, y) => y.CanExecute = CanMyRoutedCommandBeExecuted));
  }
}


3. Finally define a view with a ViewModelControl and some templates for your ViewModels and DataModels:

<Window
xmlns:baseViews="clr-namespace:Namespace.Of.ViewModelControl"
xmlns:models="clr-namespace:Namespace.Of.ViewModels"
...>
  <Window.Resources>
    <DataTemplate DataType="{x:Type models:MyViewModel}">
      <Button Content="Execute MyRoutedCommand" Command="model:ViewCommands.MyRoutedCommand" />
    </DataTemplate>
  </Window.Resources>
  <Grid>
    <baseViews:ViewModelControl Content="{Binding}" />
  </Grid>
</Window>


That's it. It works very nicely, try it.

I think I'll be posting a more complete article about this soon. In the mean time:

- What do you think?
- Want to see some real code?

Monday, September 21, 2009

TEAM's Db4o Management Studio v0.1.0 is out

Many times in the latest couple of months I've found my self hoping for a tool that would allow me to inspect a db4o database without using the classes that were used to save the data.

One of these situations is when I'm migrating an old classes' schema into a new one, and I really need to see what's inside the database to implement the migration.

After so much hoping and dissapointment on the Db4o Object Manager, I decided to implement a simple tool to do the job. The result is a very simple (and crude) application.

Don't expect anything fancy, but please, send any comments and suggestions, and feel free to copy the idea and make a better tool. The db4o community will thank you.

You can get the application from sourceforge here

Thursday, August 27, 2009

TEAM's TimeTracker v2.2.0 is out

A long time ago I built an application to manage the time me and my co-workers spent at work. I built the tool to be very simplistic and useful.

Although I published it in SourceForge since the beginning, I didn't have notice of any other users of the application until recently, on July 15th 2009, when Softpedia included the application in their database:



From that moment on some people started using it and it became obvious that the errors which we were already used to were a blocking issue for most people out there. That's why I've spent some time fixing those errors (and hopefully not introducing new ones).

Thanks to Randy Schultz for reporting most of the issues, and thanks to my former co-workers in Expectra for using the application no matter what, the TEAM's TimeTracker v2.2.0 is available at SourceForge:

http://sourceforge.net/projects/wpf-timetracker/

This version is able to automatically migrate the old data you had if you were using v0.1.0.

I hope you like it.

Sunday, July 26, 2009

Romialyo.NET SDK is public (with an ESB)

I've decided to publish the libraries I use for development in most of my projects. You can get it here, at github. It currently contains:
  • Several extensions to the .NET Framework I found myself re-coding many times.
  • An Enterprise Service Bus implementation, inspired in the good concepts from nServiceBus and RhinoESB.


Romialyo's ESB supports MSMQ and in-process message sending.

This ESB has become central to most of my projects so it was very important for me to have this code in a unique location and manage its versions properly.

Romialyo's ESB was started from the ground, trying to improve on nServiceBus code which I found hard to compile, extend and understand. The biggest stopper I found with nServiceBus was that it was too difficult for me to create an InProcess transport that will allow me to use the ESB as an Event Aggregator to communicate views in Smart Client applications.

In this blog post, Jeremy D. Miller exposes his conclusion about the "Event Aggregator = Service Bus" idea (braindump #12). I've been using a service bus with an events based in-process transport as the Event Aggregator in my applications for a while, and I must say I've found the idea very attractive.

Wednesday, July 15, 2009

TEAM's TimeTracker es realmente público ahora

Hoy he recibido una sorpresa: TEAM's TimeTracker pasa a formar parte de la base de software de Softpedia.

Siempre pensé que la aplicación era útil, sin duda lo ha sido para mi y para los Expectros que la utilizan a diario, pero tampoco hay dudas de que tiene demasiados errores.

Creo que esta noticia hará que le dedique un tiempo a pulirla un poco.

Thursday, July 9, 2009

Verificación automática de las reglas de negocio

Contexto:
- Empresa muy grande e informatizada.
- Gran volumen de datos.
- Lógica de negocio complejísima.
- La empresa depende en todos los aspectos de que los procesos informáticos funcionen correctamente.

Pregunta:
¿Es posible que todas las verificaciones de los procesos sean manuales, que haya muchísimas dependencias temporales (X debe ejecutarse después de Y) y funcionales entre todos los procesos, y que NO SE DERRUMBE TODO?

Al parecer sí. El coste es alto: muchísimos desarrolladores y muchísimo esfuerzo extra, pero funciona.

Wednesday, April 22, 2009

Revisando Composite Application Block (Prism)

Después de descartar dedicarle tiempo a Caliburn, le echo un vistazo a Prism. El vistazo es rápido porque no necesito mucho tiempo para ver cosas que no me gustaría ver en mi aplicación.

- Me parece demasiado complejo. Over-architected sería la palabra en inglés. Se parece demasiado al MVP del Composite Web Application Block. Es una complejidad que sufrí una vez y que evitaré siempre que esté en mis manos.
- ¿Un HelloWorld con 2 proyectos, 4 clases y 3 XAML? Sólo eso es una mala señal, aunque por sí mismo no signifique nada.
- Al igual que Caliburn, crea demasiadas abstracciones nuevas encima de WPF. Esto implica mayor curva de aprendizaje y mayor probabilidad de perder el tiempo invertido.
- También se utilizan string mágicos para referenciar elementos importantes de la aplicación, como las "regiones".
- La comunicación entre "módulos" es muy compleja.

El código publicado en codeplex no se corresponde con la última versión.

Conclusión

Seguramente, al igual que Caliburn, Prism implementa mucha funcionalidad, pero el precio de utilizarla me parece demasiado alto: curva de aprendizaje, cantidad de abstracciones por encima de WPF, complejidad impuesta a mi aplicación.

Revisando Caliburn

Estoy revisando Caliburn y
no me ha gustado lo que he visto. Hago un resumen muy rápido e incompleto.

Sólo estoy revisando los ejemplos y lo que veo es:

- Demasiado e incorrecto uso de atributos. Preview, Rescue, etc contienen lógica de ejecución. Me parece muy poco intuitivo y alejado del modelo tradicional espeficar esos aspectos mediante atributos.
- Con los atributos, se pierde todo el chequeo estático de tipos, utilizando para casi todo strings mágicos.
- Demasiada lógica en los XAML. Por ejemplo, se enlazan comandos, acciones, etc, indicando en el propio XAML, mediante una sintaxis inventada, a qué elemento de la vista se le va a asignar el resultado de una operación realizada en un comando o en el Presentador. El compilador tampoco detecta errores aquí.
- Demasiadas abstracciones adicionales por encima de WPF, lo que aumenta la curva de aprendizaje y el peligro de aprender algo que no será útil en otros entornos.

En mi opinión, esto se aleja del ideal:

- Mantener todo lo posible el chequeo estático de tipos!
- Toda la lógica está en los ViewModel.
- Ninguna lógica en el XAML. En el XAML sólo debe hacerse DataBinds contra las propiedades del ViewModel.
- Los XAML de la aplicación deberían ser la mayoría DataTemplates, uno por ViewModel.

Conclusión

Quizás Caliburn ofrezca muchas funcionalidades ya implementadas, pero utilizarlo:

- Me obligaría a aprender todo un modelo nuevo que se aleja demasiado de M-V-P y de WPF.
- EL framework te dirije a una aplicación sin chequeo estático de tipos, y muy parecida a un código espaghetti enlazado mediante strings mágicos.

Tuesday, March 10, 2009

Cuba en el Clásico Mundial de Pelota

Al parecer, aquí se pueden ver los juegos de Cuba en vivo! No lo he comprobado.

telerebelde.ambacuba.org

Clásico Mundial de Pelota (béisbol, baseball, o como quiera que le llamen)

Aquí se puede ver el clásico en VIVO! Por supuesto, sólo transmiten un juego a la vez. La resolución no es ideal, pero es gratis, y algo es algo.











Thursday, February 19, 2009

Descripción del proceso de aprendizaje: de "Novato" a "Experto"

Level 0: I overcame obliviousness
I now realize there is something here to learn.

Level 1: I overcame intimidation
I feel I can learn this subject or skill. I know enough about it so that I am not intimidated by people who know more than me.

Level 2: I overcame incoherence
I no longer feel that I’m pretending or hand-waving. I feel reasonably competent to discuss or practice. What I say sounds like what I think I know.

Level 3: I overcame competence.
Now I feel productively self-critical, rather than complacently good enough. I want to take risks, invent, teach, and push myself. I want to be with other enthusiastic students.

Obtenido de http://www.codinghorror.com/blog/archives/001226.html, que a su vez lo extrajo de una "Google conference" de James Bach http://video.google.com/videoplay?docid=6852841264192883219

Monday, February 2, 2009

DDDD, un paso adelante

Distributed Domain Driven Design me está pareciendo la arquitectura más completa y realista. Tiene una respuesta (en forma de patrón) para cada aspecto, y no permite que la arquitectura implique una seria afectación de la eficiencia, como es el caso del DDD que he venido aplicando hasta ahora.

El fórum de discusión es muy activo, y Udi Dahan y Greg Young aclaran todas las dudas con muchísima seguridad y lógica.

Estoy entusiasmado con esta nueva opción. Este es mi resumen:

From Udi:

"The problem is thinking about the form as editing the underlying entity.
Think of the form as the way the user tells the system which task they wish to perform.
A command from the user.
Push that command down through your architecture."

"No manipulating domain objects directly on the client in a distributed system.
Changing data involves sending a command to a “service” (not SOA)."

"Even if you went to the server, right then and there, and got the most up to
date data, a second after the user looks at it - it's already stale.
Somebody else may have changed it - unless you're doing pessimistic locking."

"Just use Guids to identify your entities and you’re all set in terms of correlation – no need to wait for the server to give you an Id back."

Thursday, January 22, 2009

Utilizar Expression para lograr AOP: primitivo pero interesante

Esta es una idea que me vino a la cabeza y que no tengo tiempo de desarrollar ahora. Y tampoco quisiera que se me olvidara.

La principal dificultad a la que se enfrentan los frameworks que ofrecen AOP es la intercepción de las llamadas a los métodos. (Por cierto, este framework luce prometedor: PostSharp)

¿Y si al escribir el código los desarrolladores utilizaran un método que recibe como parámetro un Expression, un Action o un Function, que sirva para aplicar aspectos?

Debo mirar con más profundidad.

Thursday, January 15, 2009

Tenemos un equipo de probadores! (Testers)

Me gusta pensar que mis opiniones al respecto han tenido algo que ver con que finalmente contemos con un equipo dedicado exclusivamente a probar como lo haría un usuario.

No creo que esté muy bien articulado, pues a pesar de estar en la habitación contigua no tenemos interacción con estos testers más que a través de los jefes de proyecto.

Aún así, creo que es un paso de avance y mejorará la calidad de los productos que entreguemos.

Dado el paso de asumir el gasto necesario ahora sólo falta que se interesen por obtener el mayor beneficio a cambio, implementando mecanismos de interacción entre equipo de pruebas y equipo de desarrollo que favorezcan un ciclo rápido de retroalimentación mutua.

Peligroso UpdatePanel

El UpdatePanel es una golosina para los desarrolladores. Es muy fácil de utilizar y da al usuario una magnífica impresión: mira, las páginas no pestañean todo el tiempo!

Sin embargo, al menos para nosotros, ha resultado una trampa. No he hecho un análisis profundo de toda la funcionalidad que provee, pero hemos encontrado muchísimos problemas:

  1. Al combinarlo con JavaScript.
  2. Al combinar varios UpdatePanel... las interacciones son difíciles de preveer y las consecuencias nefastas.

En honor a la verdad, no toda la culpa es del UpdatePanel. WebForms en sí mismo también ha influido bastante. Por lo tanto:

  1. Migremos a MVC!
  2. Si tienes que usar WebForms, no utilices el UpdatePanel sólo porque es fácil, sin haber estudiado las limitaciones que impondrá a la aplicación.

Wednesday, January 14, 2009

Buen código == Sentido común y cohesión == satisfacción

Si programamos como si estuviéramos creando una teoría llegaremos a un punto en la vida de nuestra aplicación en el que hacer cambios y mejoras se convertirá en el placer de descubrir que "sólo" tendremos que reutilizar lo que ya está hecho.

En una teoría todos los elementos, salvo los axiomas, se derivan unos de otros y es "fácil" crear nuevos teoremas a partir de los que ya se conocen mediante derivaciones lógicas.

Este punto no es fácil de alcanzar, requiere de una buena guía (léase arquitectura + convenciones) y sobre todo de una gran disciplina y esfuerzo por mantener la cohesión de lo que se genere.

Creo que en esto consiste "programar bien" y es lo que persiguen por diferentes vías las metodologías existentes.

En la analogía, que no pretende ser muy estricta, en nuestro programa crearemos nueva funcionalidad a partir de la existente, ya sea reutilizando o modificando. Mientras más fácil sea comprender lo que ya se ha hecho, y cómo funciona, más fácil será reutilizarlo y modificarlo para lograr nuestro objetivo.

Mantener la cohesión requiere aplicar las "buenas prácticas", en especial:
  • Asignar nombres explicativos absolutamente a TODOS los elementos (métodos, variables, clases) por muy insignificante que parezcan.
  • Aplicar SIEMPRE las reglas de nomenclatura que se decidan, de forma que cada nombre contenga la mayor cantidad de información posible para un lector.
  • Mantener la relación entre los nombres y la funcionalidad. Sí, aunque requiera renombrar un archivo en el control de versiones.

Muchas veces he visto como alguien (incluyéndome) crea un pedazo de código "rapidito" para resolver un problema, sin pensar a largo plazo. 2 horas después este pedazo es incomprensible para todo el mundo (a veces incluso para la misma persona que lo escribió), y por lo tanto, no reutilizable ni modificable.

También he visto como se hace una modificación de la funcionalidad sin adaptar los nombres de los elementos involucrados, con idénticas consecuencias.

Estos fragmentos de código actúan como aglutinantes y en poco tiempo habrá más código dependiente de este que tampoco será reutilizable ni modificable.

Lo mínimo que debe hacer un buen programador es mantener la cohesión al nivel que le corresponda:

  • Desarrollador: clases, funciones, propiedades, variables.
  • Arquitecto: todo

Desafortunadamente, las reglas de negocio que debemos implementar seguramente están entre las teorías con menos cohesión que existen. A veces incluso ni se pueden considerar teorías porque hay reglas que se contradicen! Pero ya eso no está en nuestras manos. Lo que podemos hacer es mantener el desorden al mínimo, localizado en la implementación de esas reglas.

Monday, January 12, 2009

Sin llegar al absurdo: entrega al cliente algo sobre lo que pueda opinar

La comunicación con el cliente es mucho más sencilla cuando ambas partes pueden referirse a algo tangible. Por lo tanto, creo que siempre que sea posible se debe hacer un despliegue temprano de la aplicación y fomentar la crítica del cliente.

http://feeds.jeffreypalermo.com/~r/jeffreypalermo/~3/501921276/

Esto tiene el incoveniente de que para el cliente siempre es difícil determinar la profundidad con la que debe probar una funcionalidad, pero si se gestiona bien y con tacto esto es mucho mejor que obtener la opinión del cliente cuando ya se ha avanzado mucho en el desarrollo.