Agiles 2011: día 1

No tengo palabras para comenzar el relato, curioso, nunca me había pasado. Resulta que no sé como describir lo que fueron las primeras horas del evento en las que estuve trabajando en la registración. Diría que fue terrible, pero en el buen sentido, mucha adrenalina, gran trabajo de equipo la mejor onda y algunas cosas para mejorar.

Luego de cumplir con mi compromiso en el área de registración, asistí a la sesión «From Estimate from commitment«. La sesión estuvo bien, comenzó con un repaso de algunos conceptos de agile y estimación en general. Luego, el core de la sesión estuvo alrededor de un método de estimación basado en PERT. Una vez presentado el método, lo ejercitamos trabajando en grupo. Personalmente yo ya conocía PERT (fue una de las cosas que me enseño Juan cuando lo tuve como profesor en FIUBA) y al mismo tiempo cuando trabajaba en Snoop también usábamos una variante del mismo.

Durante el almuerzo estuve colaborando sirviendo bebidas junto con @pablitux (a la pasada MartinA nos sacó una foto http://yfrog.com/kg27ooij).

Ya por la tarde, estuve en el workshop de James Shore, simplemente excelente. No participé del workshop, sino estuve en mi rol de organización, atento a cualquier requerimiento que pudiera tener James durante la sesión. El workshop estuvo enfocado en Product Management y durante el mismo, James presentó 6 técnicas para llevar a cabo esta práctica. Estuvo muy bueno, yo temía que tuviéramos que afrontar alguna situación tensa dado que el cupo de asistentes estaba limitado. Pero por suerte, James tuvo la buena voluntad de aceptar a las 6 personas adicionales que se acercaron al comienzo. Como si fuera para contrarrestar esta buena intención de James, un par de asistentes se retiraron 45 minutos antes de que finalice la sesión dejando en banda a sus respectivos grupos de trabajo. Sinceramente, esto me parece una gran desconsideración y falta de respeto, no solo hacia el orador y los participante del workshop, sino también hacia las personas que podrían haber ocupado esos lugares. Seamos claros, si el orador explica que la sesión consiste en trabajo en equipo y que dura 2 horas, se sincero y si sabes que no vas a quedarte las 2 horas, andate y dejá tu lugar a alguien que esté dispuesto a quedarse la sesión completa. En fin, no vale la pena dedicar más palabras a esta cuestión. Saqué un monto de cosas del workshop, pero les voy a dedicar otro post.

Finalmente, cerramos este primer día con una retrospectiva de organizadores y voluntarios, para identificar los puntos de mejora.

Aquí pueden ver algunas fotos que saqué.

Continuará…

Agiles 2011: La previa

Durante los próximos 3 dias se llevará a cabo en las instalaciones de la Universidad de Palermo (Buenos Aires, Argentina) la cuarta conferencia latinoamericana de métodos ágiles. Hoy a la tarde nos reunimos los miembros del equipo organizador y los voluntarios en las oficinas de Kinetica, para ajustar detalles operativos del evento. Con colaboradores de Argentina, Bolivia, Chile y Perú trabajando codo a codo, armamos las más de 500 bolsas que entregaremos a los asistentes al registrarse.

Luego del armado de bolsas, definimos algunas cuestiones operativas respecto de la registración, la coordinación de las sesiones y la asistencia a los oradores.

Finalmente nos quedamos un grupo reducido, trabajando en algunos detalles más: Ale y Martín preparando el discurso de apertura de la conferencia y el resto (Esteban, Julian, Fabián, Emilio, Adrian, Pablo y yo) trabajando en tareas diversas como el armado de credenciales, las listas de registro, los carteles para las sesiones, etc.

Ya estamos a un par de horas, mi despertador sonará a las 6.30, pues 7.30 es la cita en la universidad. Por eso, en cuanto termine este post pongo mi disco de Dancing Mood y soñar con angelitos.

Pharo: cortito y al pie

Desde hace dos semanas que vengo con días muy intensos y la cuestión no va a aflojar por al menos dos semanas más: corrección de trabajos prácticos y parciales de facultad, Agiles 2011, Codecamp y eventos familiares entre otras cosas. Pero a pesar de todo esto no quería dejar compartir un post que hizo Sven Van Caekenberghe en la lista de distribución de Pharo motivado por este otro post de  Marcus Kazmierczak.

El titulo del post fue «One Liners to Impress Your Friends» y estos son los items que me parecieron más copados de los que incluyó Sven.


"---  multiplicar cada item de una lista por 2 ---"

(1 to: 10) collect: [ :each | each * 2 ]

"--- Sumar una lista de numeros: 4 opciones distintas  ---"

(1 to: 1000) inject: 0 into: [ :sum :each | sum + each ]

(1 to: 1000) sum.

"--- Leer un archivo ---"

(FileStream fileNamed: 'data.txt') contentsOfEntireFile

"--- Feliz cumpleaños ---"

1 to: 4 do: [ :each | Transcript crShow: 'Happy Birthday ', (each = 3 ifTrue: [ 'dear Mr. President' ] ifFalse: [ 'to You' ]) ]

"--- Filtrar una lista de numero: 2 opciones ---"

#(49 58 76 82 88 90) groupedBy: [ :each | each > 60 ]

"---  Consumir un servicio XML o JSON ---"

XMLDOMParser parse: (ZnNeoClient new get: '<a href="http://search.twitter.com/search.atom?&q=pharoproject" target="_blank">http://search.twitter.com/<wbr>search.atom?&q=pharoproject</wbr></a>')

JSJsonParser parse: (ZnNeoClient new get: '<a href="http://search.twitter.com/search.json?&q=pharoproject" target="_blank">http://search.twitter.com/<wbr>search.json?&q=pharoproject</wbr></a>')

"---  Encontrar el mínimo/máximo en una lista ---"

#(14 35 -7 46 98) min

#(14 35 -7 46 98) max

That’s all folks.

MMP Video Editor (RCE): adding configuration parameters

If you want to extend RCE by adding a new module, it is possible taht you need to add some configuration parameters for the module’s logic. Depending of the nature of your module, you will set the configuration parameter when deploying the application in your server or using another approach you could allow the user to modify this configuration parameters in the application UI.

To analyze these two situations let’s suppose we need to implement an alerts module to check for alerts provided by a remote service. This new module depends on a integer parameter that sets the interval the alert service will be checked. This parameter cannot be modified by the user. What the user can decide is to enable or disable the alerts module while running the application.

So, we will create a new module following RCE architecture (that is based on Prism) and we will add our new module to the ModuleCatalag in the shell project.

To manage the interval parameter, we will add a new entry in the Settings.xml file in the RCE.Web project.

<Parameter Name="AlertsInterval" Value="10000"/>

Then, to access this parameter, we can use the IConfigurationService provided by the RCE.Infrastructure assembly. We just have to declare this interface to be injected by the container into our instance.

public AlertsPresenter(IEventAggregator eventAggregator, IAlertsView view, IAlertService alertService, IConfigurationService configurationService)
{
   int interval = configurationService.GetParameterValueAsInt("AlertsInterval").GetValueOrDefault(1000);
   // perform additional initialization logic here
}

Note that GetParameterValueAsInt is an extension method and to be able to use it, you have to add a using statement for RCE.Infrastructure.

To manage the other parameter that can be modified by the user to enable/disable the module, we should use the settings module, just to be consistent with the application. As it is provided, the settings module was not designed in a extensible way, I mean, if we need to manage a new parameter in the settings view, we have to modify the settings module each time we want to add something new. We could modify the settings module to handle our specific parameters, but instead of that we will modify the settings module to make it more flexible and avoid future modifications.

We will start by adding a new Region inside the Settings view, to allow each new module to add its own settings view. To do this, we have to include the following declaration at the beginning of the file SettingsView.xaml file.

<UserControl xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"&nbsp; x:Class="RCE.Modules.Settings.SettingsView" xmlns=<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&nbsp; xmlns:d="http://schemas.microsoft.com/expression/blend/2008"&nbsp; xmlns:mc=<a href="http://schemas.openxmlformats.org/markup-compatibility/2006">http://schemas.openxmlformats.org/markup-compatibility/2006</a>&nbsp; xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation" mc:Ignorable="d" xmlns:Commands="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation" xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" <br>xmlns:Behaviors="clr-namespace:RCE.Modules.Settings.Behaviors" BorderThickness="0" d:DesignHeight="926">

Then, we need to add a new row to the container Grid

<RowDefinition Height="80"/>

Finally, we add the new region in the new row at the end of the file.

 <Border Grid.Column="0" Grid.Row="14" Background="{StaticResource ComboBrush}" CornerRadius="8,8,8,8" Grid.ColumnSpan="2" HorizontalAlignment="Center" Width="350" VerticalAlignment="Center" Height="85" Style="{StaticResource SharedBorderStyle}">
  <ItemsControl Regions:RegionManager.RegionName="ExtendedSettingsRegion" /></Border>

Now, we need to add the ExtendedSettingsRegion region to the RegionNames class in the RCE.Infrastructure project.

public const string ExtendedSettingsRegion = "ExtendedSettingsRegion";

At this point, if we run the application, we will see the following Settings view.

 image

Now, each new module should define a view to be loaded in the ExtendedSettingsRegion (of course it is not mandatory, it is just in case the module requires to manage settings). In the case of our AlertsModule we have just 3 visual controls, a textblock, a check box and a button.

<UserControl x:Class="RCE.Modules.SWUAlerts.Views.AlertsSettingsView" xmlns=<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a> xmlns:x=<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml</a> xmlns:d="http://schemas.microsoft.com/expression/blend/2008"&nbsp;&nbsp;&nbsp;&nbsp; xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"&nbsp;&nbsp;&nbsp;&nbsp; xmlns:Commands="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mc:Ignorable="d"&gt;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Grid&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Grid.ColumnDefinitions&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ColumnDefinition Width="0.5*"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ColumnDefinition Width="0.5*"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Grid.ColumnDefinitions&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;Grid.RowDefinitions&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;RowDefinition Height="0.5*"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;RowDefinition Height="0.5*"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/Grid.RowDefinitions&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;TextBlock Grid.Column="0" Grid.Row="0" Text="Alerts enabled" FontWeight="Bold" FontSize="11" Foreground="{StaticResource ForegroundBrush}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,5,0"/&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;CheckBox x:Name="AlertsEnabled" Grid.Column="1" Grid.Row="0" IsChecked="{Binding Path=AlertsEnabled, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" VerticalAlignment="Center" />
<Button Grid.Column="1"&nbsp; Grid.Row="1" Content="Apply" Commands:Click.Command="{Binding ApplyAlertsSettignsCommand}" VerticalAlignment="Center" Width="110" Margin="0,0,10,0" Cursor="Hand" HorizontalAlignment="Left" Foreground="{StaticResource ForegroundBrushAlternative}" Background="{StaticResource ToolBarBrush}" Template="{StaticResource SetttingsButtonTemplate}"/></Grid>
</UserControl>;

image

The other extension point to consider is the persistence of the parameter. The settings module manages the persistence using the configuration service, so we can use it and it will be almost the same we did for the static parameter. We just have to declare the dependency to be injected in the constructor and adding a new entry in the settings file.

public AlertsSettingsPresenter(IAlertsSettingsView view, IConfigurationService configurationService){..}

 

<Parameter Name="AlertsEnabled" Value="True"/>

And use it when handling the apply event.

public void ApplySettings(object parameter)
{
var valuesToUpdate = new Dictionary<string, string>();
valuesToUpdate.Add("AlertsEnabled", this.AlertsEnabled.ToString
this.configurationService.UpdateParameters(valuesToUpdate);
}

If our module needs to updated itself when a configuration value changes, we could subscribe to the ConfigurationChanged event of the configurationService.

That’s all folks! Let’s do a recap:

  • We modified the settings Module to include a new Region (ExtendedSettingsRegion)
  • We created a Settings view in our module (AlertsSettingsView)
  • We added the the corresponding presenter (AlertsSettingPresenter) to able the update of the parameters

Below is a screenshot of the final project of my module.

image 

TODOs:

The way this solution is implemented requires each module to handle the persistence, I mean, each module has to provide a “save” button and call the configuration service. I think that applying a refactoring this logic could be handled by the settings module, but that is part of another post.

Code Camp 2011 >> Allí voy

La semana pasada me confirmaron la aceptación de mi propuesta de sesión para este ya clásico evento impulsado por Microsoft.

Este año la cita es el sábado 15 de Octubre en las instalaciones de la UAI. Como de costumbre, el evento es gratuito pero con previa registración y dura todo el día. No estoy seguro de la hora de comienzo, pero dado que mi sesión está agendada para las 10.20 hs estimo que el evento comenzará a las 9.

En esta ocasión voy a estar presentando junto a mi colega Dario Seminara, una sesión titulada «Gestión de la configuración con NutGet y Git». Los interesados pueden dar un vistazo a lo que vamos a hablar en el sitio del evento, donde también pueden registrarse.

Otra vez a rendir examen

Hace un par de días volví a rendir un examen en la universidad luego de más de 4 años (si no me falla la cuenta, el último examen lo rendí en 2006). En esta ocasión, fue el examen final del seminario de Educación a Distancia. La modalidad del examen fue novedosa para mi. La evaluación fue en grupos de 8 personas, cada uno de los 8 debió elegir un sobre con las preguntas del tema que deseaba contestar.O sea, cada uno elegía el tema, pero no las preguntas, las cuales estaban selladas dentro del sobre. En mi caso elegí conceptos generales de educación a distancia. Si bien aún no tengo la nota, estimo que me fue bien. Ups! ahora que lo escribo, caigo en la cuenta, ¡recorcholis! ¿porque diablos no pregunté la nota? mmm, debe ser porque tenia la seguridad de que me fue bien. Bueno, en fin, volvamos a la dinámica. Cada uno por turnos, abría su sobre y contestaba las 3 preguntas indicadas. A medida que iba contestando, la profesora metía algún bocadillo, daba participación al resto de los alumnos o bien repreguntaba. Durante el examen, tomé nota de algunas cosas, un par de frases sueltas, que me llamaron la atención entre las que se destaca:

El aprendizaje es interno, mientras que la enseñanza es externa.

Redondeando, si bien creo que hay algunas cosas por mejorar, la materia me gustó y aprendí muchas cosas que ya estoy intentando poner en práctica.

Variables de clase y de instancia en Smalltalk

Este tema incluye algunas particularidades que me parece en general no se le presta mucha atención y por ello hoy quiero dedicarle un par de líneas.

Analicemos la definición de clase CuentaBancaria:

Object subclass: #CuentaBancaria
	instanceVariableNames: 'numero saldo'
	classVariableNames: 'SiguienteNumero'
	poolDictionaries: ''
	category: 'algo3-ejemplos'

instanceVariableNames, indica las variables de instancia, también conocidas como atributos de instancia. En Smalltalk, estas variables tienen visibilidad protegida aunque en general se las trata como si fueran privadas. En este caso tenemos las variables de instancia numero y saldo. Un detalle interesante es que las variables son protegidas de las instancia, ¿que significa esto? supongamos que tengo dos instancias de la clase CuentaBancaria: cuenta1 y cuenta2, entonces cuenta1 no puede acceder al atributo numero de la cuenta cuenta2, pues si bien cuenta2 es una instancia del mismo tiempo, resulta que otra instancia y aqui la protección es a nivel de instancias.

classVariableNames, como su nombre sugiere son variables de clase, lo cual significa que son accesibles por el objeto clase, pero al mismo tiempo también son accesibles y compartidas por todas las instancias de la clase, o sea, si una instacia modifica el valor de dicha variable, dicho cambio afecta a todas las instancias. En este caso tenemos tenemos el siguienteNumeroDisponible como variable de clase, la cual es incrementada por cada instancia cada es inicializada.

initialize
	saldo := 0.
	numero := siguienteNumero.
	siguienteNumero := siguienteNumero + 1.

Un punto importante para considerar es que esta variable también es accesible por la clase CuentaBancanria.

Por otro lado, si vamos a la definición de la clase CuentaBancaria y vemos la parte de clase, veremos.

CuentaBancaria class
	instanceVariableNames: 'MaximoNumero'

instanceVariablesNames, en este caso representa las variables exclusivas del objeto clase y como tales son accesibles por la clase, pero no por las instancias de  la clase. Un detalle interesante respecto de estas variables es donde inicializarlas. Bien, en general se suele agregar un método de clase que se encarga de inicializarlas, pero ojo este seria un método de clase.

Bien, por último, si volvemos a la definición de la clase CuentaBancaria, veremos que aún nos queda por mencionar los poolDictionaries. Estas variables son variables compartidas por instancias de distintas clases.  Es algo relativamente raro (al menos a mi parecer) y por eso es que no se ocurre como utilizarlas en el ejemplo, pero prometo escribir otro post al respecto.

Para finalizar les ofrezco un gráfico para intentar resumir el ejemplo.

(gracias Mariano por la correción)

 

 

 

Google en la televisión

Estaba mirando televisión y en el corte publicitario vi una un aviso de Google Chrome. Sinceramente me tomó por sorpresa, no por ser Google, sino porque no recuerdo haber visto anteriormente una propaganda de software (que no sean juegos) en televisón abierta. Ahora pensándolo un poco más, creo que en algún momento vi un aviso de Windows u Office, pero no estoy seguro. En fin, solo quería compartir la curiosidad.

FIUBA++

La semana un docente de física en Fiuba que cursa conmigo en UNLP, me comentó que habían implementado una modalidad de cursada semi-presencial para los alumnos recursantes  de física 1. Me quedé anonadado, en primer lugar me parece una iniciativa simplemente excelente y el hecho de que sea en Fiuba me sorprende más y me alegra el doble.

Como graduado y docente de Fiuba, suelo ser muy crítico hacia la facultad, pero en esta ocasión, me saco el gorro y hago una referencia, ¡aguante Fiuba!