Así fue mi paso por Fon

Hace unos meses tuve la suerte de ser contratado por Fon para impartir un curso de TDD a uno de sus equipos de desarrollo en Madrid. Una oficina chulísima y un equipo entregado que prestó atención máxima desdel el minuto 1.

IMG_20151202_112556

Fon es una empresa de la que he oído hablar practicamente desde sus orígenes porque sonaba mucho en el mundillo geek desde siempre. Tenían fama de hacer las cosas bien. Así que tenía ganas de visitarles y ver qué se contaban hoy en día donde el Wifi ya no parece tan importante. Sin embargo me contaron que lo están petando con el roaming wifi en varios países.

Lo único que me faltó para que hubiese salido todo del 10 es conocer a Daniel Brandi que justamente esa semana estaba en un evento en Londres y no nos pudimos ver. Me sorprendió gratamente que muchos de los participantes en el curso ya me conocían y se habían preparado preguntas para sacarle el máximo partido a esos dos intensos días de formación.

IMG_20151202_112633

Agradezco especialmente a Joan Fisbein la atención, el apoyo prestado y las agradables conversaciones durante la comida.

Parece que el curso cambió la forma en que el equipo ve los tests, tanto en calidad como en cantidad. La gente se dió cuenta que la cobertura no es un objetivo en sí mismo sino que lo importante es crear unos tests mantenibles que mantengan un buen compromiso entre seguridad y mantenibilidad.
Las conversaciones fueron muy interesantes y la gente muy maja.

Además en este curso pudo venir conmigo nuestro aprendiz Miguel A. Viera y facilitar alguno de los ejercicios en el segundo día. Miguel se quedó alucinado con la oficina.

IMG_20151201_121617

Ahora mismo Fon está buscando desarrolladores Java senior. Es un buen momento para enviarles un CV si estas buscando nuevos retos.

Así viví el rodaje de NMNL Episodio 2

Ni Monos Ni Lagartos, Episodio 2:

No tenía ni idea de qué era esto de "Ni monos ni lagartos" NMNL, (más allá de la pegatina de Autentia del mono con el lagarto en la cabeza con atajos de teclado de Vim) porque cuando Isabel Rodriguez me llamó para decirme que habían pensado en mí para el segundo episodio, el primero todavía no se había emitido. Así que pense... bueno serán un par de preguntillas rápidas al estilo de otras entrevistas cortas que he hecho con Autentia. Pero después me dijo que vendrían a buscarme al aeropuerto con las cámaras y a rodar en el coche y en lo alto de no se qué puente de Madrid y pensé se les ha ido la pelota..., qué molón! me apunto!
Creo que el hecho de que pensaran en mi como protagonista de un episodio de NMNL fue que iba a impartir un taller de Refactoring en Autentia. Es lo bueno que tiene recordarle a la gente que estas ahi, que pueden contar contigo.

NMNL es algo así como "el Salvados" del mundo IT 🙂 un programa donde entrevistan a personas que ellos creen que son relevantes dentro del sector.

En este viaje me acompañaba mi hermana Raquel de tan sólo 18 años en su primera visita a Madrid y le sorprendió mucho la noticia del video, no sabía ni qué ropa ponerse. Hubo algunas preguntas sobre ella durante el rodaje pero luego quedaron fuera de los videos porque la verdad es que tres días rodando juntos no caben en los videos!
El primer día rodamos en el aeropuerto, en el coche y en la oficina de Autentia. Desde el principio me sentí super cómodo con la cálida acogida y la profesionalidad del super equipo de Autentia Media: Isabel, Alba, Leti y Sonia. Nos trataron de maravilla tanto a mí como a Raquel.
Si alguna vez tienes la suerte de que te propongan protagonizar un episodio de NMNL, no lo dudes, es una experiencia única. No importan los nervios porque no es un directo, las tomas se repiten las veces que haga falta y luego en la edición muchas cosas se dejan fuera. El equipo de Autentia se lo curra para que parezcas un gran orador, cortando pedacitos por aquí y por allá.

El segundo día rodamos en La Gatoteca, un fabuloso refugio felino en el centro de Madrid. Fue la parte de preguntas personales donde pude responder a muchas de las preguntas típicas que la gente me hace cuando vamos a comer juntos, por ejemplo preguntas sobre el veganismo o sobre nuestro pequeño refugio felino. Estuve tan agusto rodeado de gatos y tan inspirado gracias a la ayuda de Alba y del resto del equipo que grabamos mucho más de lo que cabe en un episodio de 20 minutos, que es aproximádamente lo que dura el programa. Así que en la producción han tenido el detallazo de sacar otro video, con la entrevista personal entera:

La parte más personal de la entrevista

Agradezco especialmente a La Gatoteca el gran gesto que tuvieron con nosotros al reservarnos la planta baja practicamente durante toda la mañana. Confiaron totalmente en nosotros y nos facilitaron la grabación además de ser amables y explicarnos de primera mano como funciona. Si estas en Madrid y piensas en adoptar un gatito, no dejes de visitar La Gatoteca (y si es una pareja mejor, así se dan compañía! los gatos mejor adoptarlos en pares). Es un sitio estupendo incluso para comprobar si sigues teniendo aquella alergia que te había disuadido de acoger animales!

Ese día como de costumbre tenía varias reuniones en distintos puntos de la ciudad y además la conferencia JSDay que empezaba por la tarde. En la Gatoteca estuvimos durante la mañana. Por la tarde rodamos por fuera de Campus Madrid en una plazoleta, la parte profesional de la entrevista. Mientras yo mantuve una reunión de negocio, Raquel pudo quedarse con las chicas a comer y así aprender un montón de cosas sobre cómo trabajan, cosa que a su edad es una información muy valiosa. De hecho ibamos buscando que en este viaje conociera diferentes profesionales para ir haciendose una idea de posibles oficios a aprender.

En esta entrevista hubo un pedacito donde pude hablar de nuestra experiencia en DAG (Domingo Alonso Group), el cliente que nos ha ayudado en gran medida a convertirnos en Codesai. Para una convención interna de DAG, Autentia tuvo el detalle de producir otro vídeo más, que contenía exactamente esta parte:

Hablando de DAG (Domingo Alonso Group):

Un buen pedazo de la tarde se nos fue rodando, por lo que llegué tarde al JSDay, cosa que espero que me perdonen los organizadores. Haré un post sobre el evento muy pronto, porque estuvo genial.

Se nos ocurrió la idea improvisada de que parte de mis compañeros de equipo participasen en NMNL pero como no hubo aviso con suficiente tiempo, la mayoría se había marchado de Madrid aprovechando el puente. Modesto fue el único que pudo venir a grabar a Campus Madrid pese a que era el cumple de su hija y que estaba muy cansado tras una semana intensa. Si lo hubíese sabido con antelación quizás podriamos haber estado 5 personas del equipo, pero no me lo imaginaba. Este fue el motivo de que me saliese de la sala en medio de algunas confernecias del JSDay.

El montaje final de NMNL Episodio 2, me ha parecido un montaje y una producción de una calidad enorme.

Todo el feedback sobre las entrevistas es bievenido.

Mando un fuerte abrazo a todo el equipo de Autentia por su apoyo y dedicación, sin la cual nada de esto sería posible.

El feedback que he recibido de personas cercanas es que se hace corto, que pasa muy rápido. Esta es una gran señal.

Event bubbling in C#

How to propagate an event from a low level class to a top level one:

  1.  
  2. public class TopLevel{
  3. public bool Bubbled { get; private set; }
  4. private MiddleLevel observable;
  5. public TopLevel(MiddleLevel observable){
  6. this.observable = observable;
  7. observable.Triggered += (s, e) => {
  8. Bubbled = true;
  9. };
  10. }
  11. }
  12. public class MiddleLevel{
  13. public event EventHandler Triggered;
  14. private BottomLevel observable;
  15. public MiddleLevel(BottomLevel observable){
  16. this.observable = observable;
  17. //One may be tempted to bubble like this:
  18. //observable.Triggered += Triggered;
  19. //However, Triggered is null unless there is already
  20. //a subscriber. This is a better approach:
  21.  
  22. observable.Triggered += (s, e) => {
  23. Triggered(s, e);
  24. };
  25. }
  26. }
  27. public class BottomLevel{
  28. public event EventHandler Triggered;
  29.  
  30. public void DoSomething(){
  31. Triggered(this, EventArgs.Empty);
  32. }
  33. }
  34.  
  35. [TestFixture]
  36. public class TestingEventBubbling {
  37. [Test]
  38. public void Bubbling(){
  39. var bottom = new BottomLevel();
  40. var middle = new MiddleLevel(bottom);
  41. var top = new TopLevel(middle);
  42.  
  43. bottom.DoSomething();
  44.  
  45. top.Bubbled.Should().BeTrue();
  46. }
  47. }
  48.  

Events can only be raised from within the declaring type. Unfortunately they can't be be passed in as arguments to methods. Only += and -= operators are allowed out of the declaring type. One way to stub out the event could be through inheritance:

  1.  
  2. public class BottomLevel{
  3. public virtual event EventHandler Triggered;
  4.  
  5. public void DoSomething(){
  6. Triggered(this, EventArgs.Empty);
  7. }
  8. }
  9.  
  10. public class StubbedBottomLevel : BottomLevel {
  11. public override event EventHandler Triggered;
  12.  
  13. public void RaiseEvent(){
  14. Triggered(this, EventArgs.Empty);
  15. }
  16. }
  17.  
  18. [TestFixture]
  19. public class TestingEventBubbling {
  20. [Test]
  21. public void BubblingWithStub(){
  22. var bottom = new StubbedBottomLevel();
  23. var middle = new MiddleLevel(bottom);
  24. var top = new TopLevel(middle);
  25.  
  26. bottom.RaiseEvent();
  27. //bottom.DoSomething(); will not throw the event!
  28.  
  29. top.Bubbled.Should().BeTrue();
  30. }
  31.  

But declaring the event as virtual and then overriding it, is very tricky: replacing the call to RaiseEvent to DoSomething, makes the test fail! Looks like events where not designed to be overridden. A better approach:

  1.  
  2. public class BottomLevel{
  3. public event EventHandler Triggered;
  4.  
  5. public virtual void DoSomething(){
  6. //SomeLogic would go here...
  7. Raise(EventArgs.Empty);
  8. }
  9. protected virtual void Raise(EventArgs args){
  10. Triggered(this, args);
  11. }
  12. }
  13.  
  14. public class StubbedBottomLevel : BottomLevel {
  15. public override void DoSomething(){
  16. Raise(EventArgs.Empty);
  17. }
  18. }
  19.  

Windows apps development best practices

I don't really know whether they are the best practices to be honest, and certainly there is a lot for me to learn but these are principles and practices that work well for us in the development of a complex native Windows App (Windows 8.1+) using C# and the MVVM pattern.

Files in my example (namespace + classname) :

  • Example.Views.App.xaml.cs            (Main app class)
  • Example.Views.Vehicle.xaml           (View)
  • Example.Views.Vehicle.xaml.cs       (View's Codebehind)
  • Example.ViewModels.Vehicle.cs     (View model)
  • Example.Domain.Vehicle.cs             (Domain model)
  • Example.ViewModels.AppState.cs   (In-memory app state)
  • Example.Views.NavigationService.cs (Our custom navigator)
  • Example.Views.NavigationParameters.cs (Bag of parameters to be sent to the target view)
  • Example.Domain.EventBus.cs         (Our custom
    pub-sub implementation, a singleton)

Page navigation is performed by the framework:

  1. ((Frame)Window.Current.Content).Navigate(
  2. typeof(Vehicle), vehicleId);

The first parameter is the type of the target Page and the second is an "object" intended to send any custom parameter. Such parameter is received as an argument of OnNavigatedTo method in the target page.
The code above is used to navigate from App.xaml.cs (Main page) to Vehicle (Page).

The NavigationService is an indirection level that sends the ViewModel to the View as the context object. It's used pretty much like Frame.Navigate:

  1. NavigationService.Navigate<Vehicle>(Window.Current, vehicleId);

Implementation (NavigationService.cs):

  1. public static void Navigate<T>(Window w, object context){
  2. ((Frame) w.Context).Navigate(typeof(T),
  3. new NavigationParameters{
  4. ViewModel = GetViewModel<T>(),
  5. Context = context ?? GetContext<T>()
  6. });
  7. }
  8.  
  9. private static object GetViewModel<T>(){
  10. if (typeof (T) == typeof(Vehicle)){
  11. return Factory.CreateVehicleViewModel();
  12. }
  13. ...
  14. throw new NotImplementedException("Can't navigate to such page");
  15. }
  16.  

This is how the view model is received in Vehicle's codebehind (Vehicle.xaml.cs):

  1. protected override async void OnNavigatedTo(NavigationEventArgs e){
  2. var navigationParams = e.Parameter as NavigationParameters;
  3. var vm = navigationParams.ViewModel as ViewModels.Vehicle;
  4. vm.SubscribeToEventBus(); // in case vm is a listener
  5. await vm.Initialize(); // in case of some initialization
  6. DataContext = vm; // set the DataContext at the very end
  7. }
  8.  
  9. protected override void OnNavigatedFrom(NavigationEventArgs e){
  10. if (ViewModel != null){
  11. ViewModel.UnsubscribeFromEventBus(); // release the reference
  12. }
  13. }
  14.  

Principles applied in the code snippet above:

  • DataContext is set in the last step of the method, not before. DataContext is set either in the codebehind or in xaml, but not in both places at the same time. If the DataContext is set in the xaml (DataContext="SomeProperty") and also in the codebehind, you can't guarantee which data will be finally set, race conditions could happen.
  • Pages and UI controls in general must not contain state. Avoid any field in the codebehind holding a reference to the view model. This is to prevent race conditions. We rather create a getter instead:
    1. protected ViewModels.Vehicle Vehicle {
    2. get { return DataContext as ViewModels.Vehicle }
    3. };
  • Avoid subscribing the codebehind to the EventBus, use the view model as the listener. Life cycle of the pages is controlled by the framework - this is specially important when caching pages via NavigationCacheMode="Required". Sending a reference to the EventBus will prevent the garbage collector from cleaning up the Page instance.

Avoid global statics: Although there is a single instance of AppState class - is a global singleton, we inject it into every view model that requires read or write access rather than having direct static references. The Factory knows the AppState singleton and injects it to the viewmodels. Although two different views may require the same data, we try not to store everything in the AppState but rather cache the service methods retrieving the required data and then injecting the same instance service to both viewmodels. The amount of data kept in the AppState should be minimal, basically it should contain identifiers that view models understand in order to pull data from the services. Sometimes it contains more data to avoid time consuming transformations or calculations, that's fine, it's a trade off.

Custom controls: We ended up having our own custom pages, inheriting the Page control to remove duplication from initialization process. One of such inheritors is generic: CachedPage, where T is the type of ViewModel. However in xaml you can't define a page inheriting from a generic class. To work around this minor issue we create an intermediate empty class:

  1. public class CachedVehiclePage : CachedPage<Vehicle>{}

Then in xaml we can set the type of our page to be CachedVehiclePage.

Nested user controls: When a Page contains a user control, the DataContext of that user control is the same than the Page's one. Neither the codebehind or the xaml of user control should overwrite the DataContext. The DataContext should not be set programmatically it's just inherited from the parent container. Otherwise there could be race conditions and memory leaks.

Data binding: We don't bind domain models directly to the GUI. The main reason is that double way binding requires public setters. Sometimes we create a bindable object that wraps the domain model exposing only ome properties. But we often create custom bindable objects from the domain model for the specific purposes of the view.

I'll update this post with more stuff that is working well for us.

 

 

Only one MessageDialog may be displayed

On Windows 8, a call to "await aMessageDialog.ShowAsync()" can only be made once, otherwise System.UnauthorizedAccessException will be thrown (E_ACCESSDENIED 80070005). This is a helper method to display dialogs although it's not thread-safe. It's inspired on StackOverflow answers:

  1. public static class DialogDisplayer {
  2. private static IAsyncOperation currentlyShownDialog;
  3.  
  4. public static async Task TryToShowDialog(MessageDialog messageDialog){
  5. try{
  6. RequestPreviousDialogCancelation();
  7. await WaitForUIThreadToBeReady();
  8. await ShowDialog(messageDialog);
  9. }
  10. catch (TimeoutException ex){
  11. //Logger.Information("Time out waiting for a MessageDialog to be closed");
  12. }
  13. catch (TaskCanceledException ex){
  14. CancelDialog();
  15. }
  16. catch (UnauthorizedAccessException ex){
  17. //Logger.Information("Multiple dialogs are being opened at the same time. There is a direct call to ShowAsync somewhere. Instead of using ShowAsync, use this method");
  18. }
  19. }
  20.  
  21. private static void CancelDialog(){
  22. currentlyShownDialog = null;
  23. }
  24.  
  25. private static void RequestPreviousDialogCancelation(){
  26. if (IsThereAnyOpenedDialog()){
  27. currentlyShownDialog.Cancel();
  28. }
  29. }
  30.  
  31. private static async Task ShowDialog(MessageDialog messageDialog){
  32. currentlyShownDialog = messageDialog.ShowAsync();
  33. await currentlyShownDialog;
  34. }
  35.  
  36. private static async Task WaitForUIThreadToBeReady(){
  37. var attempts = 0;
  38. while (IsThereAnyOpenedDialog()){
  39. await Task.Delay(TimeSpan.FromMilliseconds(100));
  40. attempts++;
  41. if (attempts > 5){
  42. throw new TimeoutException();
  43. }
  44. }
  45. }
  46.  
  47. private static bool IsThereAnyOpenedDialog(){
  48. return currentlyShownDialog != null && currentlyShownDialog.Status == AsyncStatus.Started;
  49. }
  50. }
  51.  

Usage:

  1. var messageDialog = new MessageDialog("Hello world");
  2. await DialogDisplayer.TryToShowDialog(messageDialog);
  3.  

Polymorphic test setup with template method

We had a kind of duplication in our tests that we didn't know how to deal with. The refactoring "Introduce Polymorphic Creation with Factory Method" explained by Joshua Kerievsky in his brilliant book "Refactoring to Patterns" gave me the solution to avoid duplicated tests.

  1. [TestFixture] public class
  2. ChangingColorWithImplicitExclusionsShould : ConfigurationTests {
  3. [Test] public void
  4. not_allow_change_when_its_compulsory_has_the_same_family_than_a_configured_equipment() {
  5. CatalogBuilder
  6. .AddEquipmentWithFamily("PR1", "Radio")
  7. .AddEquipmentWithFamily("PR2", "Radio")
  8. .AddColor("red", WithEquipmentsCompulsory("PR2"));
  9. var configuration = Agiven.ModelConfiguration()
  10. .With(Agiven.ConfigEquipment("PR1"))
  11. .Build();
  12.  
  13. Expect.CallTo(() => ExecuteChangeColor("red", configuration))
  14. .ToThrow<EquipmentsWithSameFamilyException>();
  15. }
  16. }
  17.  
  18. [TestFixture] public class
  19. ChangingInteriorWithImplicitExclusionsShould : ConfigurationTests {
  20. [Test] public void
  21. not_allow_change_when_its_compulsory_has_the_same_family_than_a_configured_equipment() {
  22. CatalogBuilder
  23. .AddEquipmentWithFamily("PR1", "Radio")
  24. .AddEquipmentWithFamily("PR2", "Radio")
  25. .AddInterior("xyz", WithEquipmentsCompulsory("PR2"));
  26. var configuration = Agiven.ModelConfiguration()
  27. .With(Agiven.ConfigEquipment("PR1"))
  28. .Build();
  29.  
  30. Expect.CallTo(() => ExecuteChangeInterior("xyz", configuration))
  31. .ToThrow<EquipmentsWithSameFamilyException>();
  32. }
  33. }
  34.  

Tests are very similar, the differences are in lines 8 and 25, and also in lines 13 and 30. First tests tries to change the color of a configuration whereas the second one tries the interior. Part of the handling business logic is the same. This is just one scenario but we had many of them, with same expected behavior for color, interior, equipment, and more. Eventually there was a lot of "duplication".

After refactoring, we have a base abstract class with the tests, exposing template methods that child classes have to implement in order to populate the catalog and also to execute the corresponding action:

  1. [TestFixture] public abstract class
  2. CantChangeConfigurationBecauseThereisImplicitExclusionWhen : ConfigurationTests {
  3. [Test] public void
  4. its_compulsory_has_the_same_family_than_a_configured_equipment() {
  5. CatalogBuilder
  6. .AddEquipmentWithFamily("PR1", "Radio")
  7. .AddEquipmentWithFamily("PR2", "Radio");
  8. AddImplicitExclusionItemWithCompulsories("PR2");
  9. var configuration = Agiven.ModelConfiguration()
  10. .With(Agiven.ConfigEquipment("PR1"))
  11. .Build();
  12.  
  13. Expect.CallTo(ChooseConflictiveItem(configuration))
  14. .ToThrow<EquipmentsWithSameFamilyException>();
  15. }
  16.  
  17. protected abstract void AddImplicitExclusionItem(string code);
  18. protected abstract Func<ModelConfiguration> ChooseConflictiveItem(ModelConfiguration configuration);
  19. }
  20.  
  21. [TestFixture] public class
  22. ChangingColor : CantChangeConfigurationBecauseThereisImplicitExclusionWhen
  23. private const string itemCode = "irrelevant";
  24.  
  25. protected override void AddImplicitExclusionItem(string code){
  26. CatalogBuilder
  27. .AddColor(itemCode, WithEquipmentsCompulsory(code));
  28. }
  29.  
  30. protected override Func<ModelConfiguration> ChooseConflictiveItem(ModelConfiguration configuration){
  31. return () => ExecuteChangeColor(itemCode, configuration);
  32. }
  33. }
  34.  

The base class "ConfigurationTests" contains just helper methods such as ExecuteChangeColor, or ExecuteChangeInterior, but no tests at all. Otherwise tests would run twice.

Refactoring katas with your own codebase

When it comes to refactoring, my preferred katas consist of experimentation with the actual code base I am working on. I just create a new branch from a certain commit, play with several refactorings and then throw it away. I usually end up with several experimental branches starting from the same commit. Sometimes if I end up with a better design, I apply the changes to the default or master branch, but that is not the goal. The goal is to improve my refactoring and design skills.

Pretty much every day, as I am coding, I find out slices of the code that smell. I find out room for a better design. However, if the code is working fine, I mean, if there are no known defects, if there is no real need to change, it's probably not worth spending work time to refactor it. At least not now. But I do write down a note about the smell to think about it later. This note often becomes the subject of the code kata.

When you approach your code base as a code kata, you don't have to care about time, you can just spend as much time as you want enjoying and learning. That code deals with a degree of complexity that is often hard to find in code katas. It's a real challenge. A big chance to improve your skills. The fact that I can experiment without any pressure, sometimes lead me to much better designs that the code base end up benefiting from. Eventually it's also good for my customers and colleagues.

Try it out and let me know whether you find it useful 😉

Reflexiones tras una emotiva CAS2015

cas2015

No habia participado en una Conferencia Agile Spain desde el 2010 que fué en Madrid, la primera. En aquel entonces iba ilusionado con 50 ejemplares en mi maleta de nuestro flamante libro de TDD, que colocamos en el stand de Plain Concepts porque amablemente me brindaron su espacio y hasta los vendían ellos. Plain aun era una empresa pequeña. Mi segundo arranque como autónomo había sido a penas un año atrás, antes del AOS 2009, primer gran evento de la comunidad, tambien en Madrid. Llevaba la ilusión de ver a todos aquellos nuevos amigos que había conocido en el AOS. No diré nombres para no dejarme a nadie fuera.

Después de aquella CAS, la avalancha de trabajo y la gran cantidad de viajes de avión que ello implica, hizo que tuviese menos disponibilidad. Me esforcé por conocer otras conferencias y otras comunidades. Quería salir por Europa y estuve en conferencias en Berlin y Londres. Y así los años han volado hasta llegar a CAS 2015. De nuevo en Madrid, la ciudad de las oportunidades para mí. Este año no podíamos faltar, teníamos que apoyar y de hecho es la primera vez que patrocinamos un evento de la comunidad. Estamos muy orgullosos de haber patrocinado, para nosotros es poner un granito de arena para que haya sido posible, aunque si no hubiesemos sido nosotros, había patrocinadores en cola, ... ¡qué éxito!

La organización de la conferencia ha sido brillante, para quitarse el sombrero. Los que me conocen saben que soy sincero, no lo diría si no lo pensase. Todo el equipo de organización y voluntarios se ha dejado la piel para que disfrutásemos. Me asombra especialmente lo tranquilos y confiados que veía a Alberto, Tino, Rubén, Vanesa, Gonzalo y Javier a pesar del monstruo que habían montado, un evento con 700 personas. Me resolvieron todos los contratiempos de última hora y me permitieron hacer la charleta de apertura cuando Javier Acero causó baja por su lesión de rodilla. Y debo decir que me lo pasé muy bien preparando la charla y luego sobre el escenario.

Desde hace unos años no me apetece dar charlas sino que prefiero formatos interactivos en plan taller donde podemos mantener conversaciones. Es porque no siento que aporte tanto valor con un monólogo durante tanto tiempo, no creo sinceramente que tenga cosas tan importantes que decir, creo que es más importante la sinergia que surge de la conversación. Pero en esta ocasión tenía que ser charla forzosamente así que como no me apetecía meter una chapa, quise que la gente se echase unas risas y se diviertiese, por lo que me propuse ensayar un baile y hacer un poco el payaso en el escenario. Pensé que sería una buena forma de abrir el día. Gracias a que Autentia lo grabó todo, queda ahí para los curiosos 😀

Había tanta gente que no pude hablar con muchos amigos, a penas pude decirles "hola" y a otros ni eso. Es lo que ocurre cuando el evento es masivo. Durante los breaks de comida y café, si me movía a buscar bebida me encontraba a gente por el camino y ya no volvía al sitio, dejaba las conversaciones a medias por más que no quisiera, una pasada. Un chute de socialización a los bestia, a lo loco. Conocí y "desvirtualice" a gente pero no nos dió tiempo a profundizar. Sabor agridulce por ese lado.
No pude asistir a las charlas que hubiese querido, de hecho practicamente no pude elegir charla pero por suerte estan grabadas.

Es muy bonito ver cómo han crecido durante estos años, profesionales de la comunidad a la que tuve la suerte de conocer en algunos de mis cursos y conferencias durante 2009, 2010, 2011... Hoy en día tengo ganas de visitarles y de trabajar con ellos porque tienen muchísimo que enseñarme. Esto es un éxito de la comunidad. Habiendome movido por otras comunidades de práctica en Europa sé que no tenemos nada que envidiar. Estamos a la altura para compartir con ellos lo que sabemos.

En cierto modo tengo la sensación de que la CAS se está distanciando del desarrollo de software, pero no me atrevería a decir si eso es bueno o malo. El taller de Tim Ingarfield y Diego Rojas fue para mi oro puro, me encantó estar allí y lo volveré a ver en video. Son unos genios. Me aportó muchísimo valor.
De alguna manera me gustaría que no nos olvidásemos de que una de las ideas de "Agile" cuando nació era acercar a gerentes y a técnicos, alinearnos todos. Y a veces tengo una sensación de que el trabajo técnico no está igual de valorado que la gestión de proyectos. Yo valoro mucho la gestion del proyecto, el cuidado de las personas, las dinámicas de equipos, la facilitación como via para quitar impedimentos... y necesito que tambien valoremos nuestro trabajo técnico. Que no se olvide que la calidad del software es tan importante como la calidad de las relaciones humanas. Que no se piense que para hacer carrera hay que dejar de programar y saltar a la gestión, sino que los que disfrutan de programar puedan hacer carrera como profesionales de la programación en sus empresas.
Me gustaría que la gente que fuese a la CAS no se fuese de allí sin saber por ejemplo que el método original se llama Extreme Programming y que estaba basado en unos valores y unos principios. Volver a recordar la raíz.
Dudo que sea buena idea que futuras ediciones de CAS sean incluso más grandes, ya me ha parecido que esta edición era gigantesca. Me pregunto, ¿por qué algunas personas hablaban de crecer en magnitud con cada edición futura, ¿qué tendría eso de bueno?
Crecer por crecer, no tiene por que ser bueno. Se me quedó grabada una idea de Joan Antoni Melé en una charla suya que vi hace tiempo donde comparaba a empresas cuyo objetivo era crecer por crecer, con un cáncer .

La keynote de Leo tuvo un fondo que me gustó mucho, el de no ser dogmaticos. Al menos eso entendí yo y me gusta porque el sentido común y el pragmatismo debe primar sobre los procesos y normas establecidos. Pero sus formas me parecieron agresivas y quizás un poco contraproducentes. Me pareció ofensiva la foto de "Manolo y Benito" cuando habló del movimiento de la artesanía del software, porque ese movimiento está buscando que se reconozca la importancia del trabajo técnico, al mismo nivel que se reconoce una buena gestión y facilitación. Ni más ni menos.
Tanto en su keynote como en alguna otra charla creí entender que se hablaba de programadores que se recrean más de la cuenta tratando de hacer florituras en el código. Creo que Artola dijo poeta del código. Bien, en mi experiencia, jamás he visitado una empresa o equipo donde pecasen de exceso de refactoring o de exceso de pair programming o mob programming. Si entendemos el refactoring por hacer el código existente, más legible y fácil de mantener y NO por un rediseño, entonces de veras que nunca he visto a nadie pecar de exceso de refactoring. El refactoring siempre se hace de menos, nunca de más. Yo recomiendo media horita de refactoring al dia, igual que el médigo recomiendo caminar media hora al día. Para que luego no haya que dedicar dias o semanas a intentar poner orden cuando está ya todo desordenado y sucio.
Lo que sí me suelo encontrar es sobreingeniería, hacer diseños de software demasiado grandes y complejos, arquitecturas gigantescas que no hacen falta. Y tambien veo gente invirtiendo tiempo en frameworks, librerías y otras herramientas, que luego no tiene un retorno de inversión. A veces se eligen porque parecen muy chulas, porque son modernas y acaban costando una fortuna. A veces esas herramientas se escogen para suplir lo que en realidad debería ser una arquitectura adaptada a las necesidades concretas del proyecto y esa falta de diseño se convierte en un cuello de botella con un coste matador.
El legendario Joshua Kerievsky en su libro "Refactoring to Patterns" habla de "underengineering" y de "overengineering". Técnicas como refactoring a diario y pair programming a diario ayudan a mitigar el riesgo de la infraingeniería y la sobreingeniería. Pero nadie dice que hay que estar todo el dia refactorizando ni todo el dia en pair programming! Uselo usted con sentido común!

En cierta forma me parece que algunos mensajes que se transmitieron pueden resultar muy confusos para los que no tienen suficiente bagaje. Me dió la impresión que echan por tierra parte del trabajo de reeducación y formación que hacemos en las empresas y en los equipos. Para mí el tema de fondo era clave y necesario pero las formas, arriesgadas.

He tenido profundas conversaciones con viejos y sabios amigos durante las cenas y el networking, que junto con el resto del evento me han hecho darme cuenta de lo mucho que la comunidad me apoya y me quiere. Pese a lo zoquete que he sido en varias ocasiones. Ver que ellos se quedan con lo bueno de uno y que son tan tolerantes con los defectos, me ha impactado. Me doy cuenta que la comunidad agile spain es un lugar donde crecer seguro, personal y profesionalmente, un sitio donde te permiten que te equivoques, que rectifiques, que cambies... y donde te apoyan a pesar de los fallos. Y esto es porque se trata de gente lista y madura. Estas conversaciones, esta revelación me está haciendo crecer. Me doy cuenta de que quiero aprender a comunicarme de forma no violenta. Que no quiero que mis malas formas estropeen el mensaje que quiero transmitir porque hieren a las personas y no ayudan a llegar a la meta, a ningún sitio. Sirva como ejemplo de lo que no quiero hacer, mi bronca con @semurat y @david_bonilla hace tiempo en twitter o mi bronca en el AOS de Tenerife.

Con esta comunidad y el apoyo incondicional de nuestro gran equipo CB&A, puedo prograsar cada día en constante mejora contínua. Podemos crecer juntos. Es un lujazo trabajar en un equipo donde, cuando te enteras que ha surgido cualquier problema ya tienes a un compañero trabajando en ello. No tienes que decirle a nadie que recoja los rollouts al terminar evento, cuando llega la hora de salir aparece Modesto con ellos al hombro. No tienes que pedirle a Alfredo que te traiga unas gafas para hacer el payaso, cuando llega la hora aparece con unas espectaculares. No tienes que pedirle a Luis que busque y hable con clientes nuestros que estaban allí en la CAS para pregunterles cómo les va, sino que cuando nos reunimos por la noche ya trae ya un resumen detallado de cada uno, con ideas y propuestas para ayudarles. No hace falta pedir feedback sincero, Nestor y Juan te lo dan así sea para ponerte en tu sitio. Fran se curró la landing page del evento por las noches aunque no pudiese venir.
Zazu estuvo ayudandome a maquetar las slides y el guión de mi presentación en todo momento.
La ilusión, las ganas y la sonrisa de nuestros aprendices, Ronny, Miguel y Dani son contagiosas fuentes de inspiración y motivación.

Gracias a todos los que han hecho posible la CAS2015, enhorabuena por conseguirlo.

Dejo por aqui las slides, ya actualizo el post con videos cuando se publiquen:

Learning with Peter

Last week I was lucky to host my good friend Peter Kofler in his visit to Gran Canaria, where he came to facilitate the Glodal Day of Code Retreat and also to work together a couple of days in our biggest project at the moment.

We've been working in the same project for a year now, our team joined the client's team to play several roles, from mentoring to developing features ourselves. Peter's visit was a fantastic learning experience and also a way to bring back principles that wear out as we face recurring issues over time. Even though we started as external consultants, the fact that we've been a year immerse in the project sometimes leading the development ourselves, changes our vision and focus. Peter's fresh vision reminded me of myself a year ago, when the gig started and reinforced my willingness to stick with my principles. Thank you Peter!

Notes that I wrote down during working sessions:

  • Code metrics is exactly what we need now to show everyone the health of the code base. We have enough code already and we must improve the readability of some tests, reorganise dependencies, clean up namespaces and some other things we know are important. A tool like Sonar of something like that will provide us with metrics to measure the improvements over time. It's definitely the time to visualize code metrics
  • Dependencies diagrams are another type of metric that we should use now that. A quick overview of how the various namespaces are related to each other.
  • There are certain areas of the hexagon suffering from "primitive obsession" code smell. We want more objects within our business domain, and less primitives.
  • More information in commit's comments. Apart from the refactoring we apply or the name of the tests turning green or red, I'll try to explain shortly what is the benefit of every single commit. The reason to change the code. I've found myself searching for particular design decisions in the commits' history and realized that the information in the comments was not enough to find out what I wanted. Example: why I moved a method to a class, extracted a class... the "why" is not in the code so it's a good idea to add it in the form of comments in the version control system.
  • I want to learn how to work with Visual Studio without the mouse, because it's faster with the keyboard only. This is an old resolution that I want to approach now.
  • I realised that our style of "mob programming" is different to the original style proposed by Woody Zuill and his team. In the original proposal, the driver is mostly "keyboarding", focusing on typing what the navigators tell him to do. Our approach is different, we have the discussion and the person who clearly sees how to translate the idea into code jumps in the keyboard and expresses it in code, no one says to the driver what should be written. The driver leads the session when he is at the keyboard. It's sometimes easier to express an idea writing some code or pseudo-code, than trying to explain how the code is going to look like, and I think this has to do with the fact that talking constantly exhausts me. It also has to do with focus, the driver is the person who can implement the discussed idea faster, who knows the code better. Whenever the driver is stuck, the navigator who knows how to carry on, asks for the keyboard and becomes the driver. I find dictating awkward and sometimes irritating. So we are not following their rule: "for an idea go from your head into the computer it MUST go through someone else’s hands.". We try not to talk whilst the driver is typing just like in pair programming, because we want the driver to be able to listen what navigators have to say, and I can't type and listen at the same time. Perhaps we are not doing mob programming at all. But it works for us.
  • In order to keep the good energy and motivation in a mob or pair prog session, it's better to give up or take a break than working without feeling like it. I need to feel that my colleagues feel like working and thus I must feel like doing so too.
  • I really like the way Peter summarized the Hexagonal Architecture, focusing on the direction of the dependencies. A simple diagram with two boxes joined by an arrow pointing from one to the other, was enough for people to understand it. Also the onion was a good idea.

Regarding the Global Day of Code Retreat, there are a bunch of things I learned from Peter and from the day itself:

  • If there are no sponsors buying food, I want to buy food myself for me and for all the participants. This year I brought the food in the afternoon but I should have brought it in the morning, when people were hungry. Next time I'll arrive in the morning with breakfast for everyone. I missed the relaxing moment of the morning break sharing some fruit and coffee or tea.
  • Whenever I talk very serious aiming to remark something important, I look like I am rude. I don't realize that until I see people's faces and by then I feel bad about it. To avoid this situation I'll think twice before sending the message. I must be quiet, talk more slowly, think from a positive angle and use positive words. Words like "no" or "not" or "don't" may be negative. I want to read about Non Violent Communication and practice it.
    As an example, during the retreat in one iteration's retrospective I said that the facilitators (Peter and me) were not there to teach. My aim was to encourage people to learn from themselves rather than expecting some kind of master class or demo from our side, but the way I said it was understood as ... "I am not here to help you, or I don't care about you" as some people told me afterwards. It had a negative impact in some people's motivation.
  • At the end of the day, after the final retrospective, in the pursuit of feedback and appreciation I talked in such an unfortunate way that made people feel in debt with us. But again I didn't realise until I saw people's reaction. My aim was to discover what benefits did participants find out during the day, what did they take away so that next time I could maximize it with specific actions or exercises.
    When it's obvious that I've dedicated time and energy working for others, I must be very careful not to express that explicitly because it will make people feel in debt which is not what I wanted.

Several friends have spoken to me about Non Violent Communication (NVC) in the last 5 years or so, I believe Diego Rojas was the first one, working with Peter was a trigger point for me to really start digging into the subject. Thank you for the recommendation Peter and for this excellent video by Marshall Rosenberg, the father of NVC:

Object references, state and side effects

C#, Java and other languages have the same behaviour when it comes to reference types.

  1. public class SomeClass {
  2. public string someField;
  3. }
  4.  
  5. var instance1 = new SomeClass(); // instance1 is a reference to an object in memory
  6. var instance2 = instance1; // instance2 is a copy of the reference
  7. instance2.someField = "changed";
  8. instance1.someField == instace2.someField // -> true
  9. instace2 = new SomeClass();
  10. instance2.someField = "changed again";
  11. instance1.someField != instance2.someField // -> true -> they are different objects
  12. instance1.someField; // -> "changed" -> nothing changed
  13.  

The dot symbol after the variable name (instance1 or instance2) accesses the actual
object referenced by that variable. So before the dot, we have a variable referencing an object, and
after the dot we have the actual object.

  1. instance1.someField;

Means: get reference instace1, then access the object, then access someField

Passing objects to functions has exactly the same behaviour, function parameters behave like variables assigned to the original arguments.

  1. public static void SomeMethod(SomeClass arg1){
  2. arg1.someField = "changed";
  3. }
  4.  
  5. var instance1 = new SomeClass();
  6. SomeMethod(instance1);
  7. instance1.someField; // -> "changed" -> field has changed
  8.  
  9. public static void OtherMethod(SomeClass arg1){
  10. arg1 = new SomeClass();
  11. }
  12.  
  13. var instance1 = new SomeClass();
  14. instance1.someField = "changed";
  15. OtherMethod(instance1);
  16. instance1.someField; // -> "changed" -> nothing changed
  17.  

Instances of SomeClass are mutable because the value of someField may be changed.
This mutation may happen mistakenly as a result of an uncontrolled access to the object via some copy of its reference, causing unexpected side effects like defects and memory leaks.
As long as the application code can reach an object - has some reference to it - the garbage collector can't free the memory allocated for that object. Short version of our desktop app architecture as an example:

  1. public static class EventBus{
  2. private static ISet<Subscriber> subscribers = new HashSet<Subscribers>();
  3. public void AddSubscriber(Subscriber subscriber){
  4. subscribers.Add(subscriber);
  5. }
  6. ...
  7. }
  8.  
  9. public class View{
  10. public ViewModel ViewModel;
  11.  
  12. public View(ViewModel viewModel){
  13. ViewModel = viewModel;
  14. }
  15. public void Init(){
  16. EventBus.AddSubscriber(ViewModel);
  17. }
  18. }
  19.  

The life cycle of the View instance is controlled by the framework, not by us. It may create a new instance every time the view is shown on screen and destroy the instance as it disappears. However we are adding a reference
to the static list of subscribers in the EventBus. As long as the subscribers list is not flushed, the garbage collector won't be able to set memory free for ViewModel and View instances, even though the view may not be even displayed. Opening that view many times will increase the memory consumption every time, that is a memory leak. In this particular case we unsubscribe the instance from the bus before hiding the view:

  1. public class View{
  2. public ViewModel ViewModel;
  3.  
  4. public View(ViewModel viewModel){
  5. ViewModel = viewModel;
  6. }
  7. public void Init(){
  8. EventBus.AddSubscriber(ViewModel);
  9. }
  10. public void Clear(){
  11. EventBus.RemoveSubscriber(ViewModel);
  12. }
  13. }
  14.  

In the case of the bus there isn't much we can do to avoid having two references to the same object in two different places, we have to be aware of this behavior. In C# there is the concept of Weak Reference but as far as I know we can't use it on WinRT (tablets).

In some other cases though we may avoid side effects:

  • Avoid more than one reference per object, avoid state
  • Keep variables local, avoid instance variables (fields)
  • When the object is a value object, design it to be immutable
  • In the case of collections, use ReadOnlyCollection when they must keep their size
  • If the object can't be designed immutable but you need to avoid state changes at all cost, clone the object returning a deep copy of it

We may be tempted to clone objects every time someone asks for a reference to them. However this may not be possible (like with the EventBus) or it may be too expensive and complex. I'd say that cloning is the last alternative and perhaps the need for it is a design smell. Who is responsible for ensuring that object references are not causing memory leaks? It boils down to the "less surprise" principle. We should design interfaces (methods) in such a way that it's obvious how references and state are going to be managed. If it looks like the consumer (the one asking for the reference) will not be aware of it and the consumer will likely make undesired changes to the object, then cloning the object could be a good defensive approach. But I would rather try to think how to make the API more expressive considering context and level of abstraction. I assume that the caller understands how references work.

If you, dear reader, provide some code examples I will be able to clarify my point with code. I'll update this post if I come up with some snippets.