miércoles, 18 de noviembre de 2015

SCRUM: StoryPoints de Historias No aprobadas Vs CarryOver

StoryPoints de Historias No aprobadas

Hay algunas preguntas que surgen relacionado a historias no aceptadas, alejadas de SCRUM, que tienen como respuesta diferentes estrategias. Ellas son:

¿Qué hacer con los puntos gastados en la historia rechazada?
¿Los puntos gastados quedan como capacity y/o se arrastran al próximo sprint para que figuren en la prómxima velocity?
¿Son puntos perdidos de la velocity o se suman a una próxima velocity?


Aquí surge el concepto de Carryover...

Carryover


El Carry Over es una User Story Comprometida y No Aceptada por el Cliente en la Demo/Review al final del Sprint. En otras palabras, es la historia no finalizada y acarreada de un sprint a otro (Kell Condon, 2015).

Estrategia 1:

El carryover conlleva puntos perdidos (Kell Condon, 2015). La velocidad debe bajar porque el equipo no fue capaz de entregar trabajo "Done" aceptado. Son puntos perdidos de la velocity actual y no se suman a una próxima velocity (ya que la velocity refleja carrera real actual de sprint y no vale sumar puntos que realmente no se hicieron en la carrera). Los puntos quemados de la historia no se arrastran ni se contabilizan en el futuro. La historia pasa al backlog para ser reestimada para ser tomada en próximos sprint. Solo se reestima el trabajo restante, cuando se toma la historia en una planning, o lo que quede por hacer si se pudo recuperar algo de lo hecho.
En esta estrategia no es necesario manejar el concepto de carryover.

Estrategia 2:


El carryover genera puntos arrastrados que contabilizan para velocity futura, o sea que los puntos quemados de la historia se arrastran y se contabilizan en el futuro (Kell Condon, 2015). La historia pasa al backlog para ser reestimada y ser tomada en próximos sprint. Solo se reestima el trabajo restante, cuando se toma la historia en una planning, o lo que quede por hacer si se pudo recuperar algo de lo hecho y se suma a lo acarreado. O sea que se reestima el SP Remanente, o sea los SP que restan para terminar esta US. Por ejemplo si se quemaron 3 SP (en sprint previo) y faltan 2 SP (de la Reestimación), la historia pesará 5 SP (Tamaño real de la US).


Referencia:

- (Kell Condon, 2015) Article, "Pick A Side: How to handle sprint carry over":

http://requirements.seilevel.com/pick-a-side-how-to-handle-sprint-carry-over

lunes, 21 de septiembre de 2015

Perl: Pairing in Pair programming without repeated

Script para formar parejas sin repetición de pares para pairing


#!/usr/bin/perl -s
# Perl Scrip to Pairing in Pair programming
# Example:

# La primera vez llamar con argumentos:
# perl pairing.pl "Dario" "Gaby" "Claudio" "Frula" "Ricardo" "Raul" "Esteban" "Adrian" 

# A partir de la segunda vez llamar sin argumentos porque los nombres fueron guardados en un archivo.
# perl pairing.pl
   
use strict;
use warnings;


# Begin main

# @ARGV is a array of command line arguments
if (scalar @ARGV == 0){
    # File input. Read from file
    my @input_argv = @{read_array_from_file('file_example.txt')};
    do_pairing_no_repeated(\@input_argv);
    }elsif (scalar @ARGV > 3){
        #ARG input. Read from arguments of command line
        do_pairing_repeated(\@ARGV);
        }else{
            print "Arguments must be more than 3! \n";
        }

# End main

# Run pairing with repeated
sub do_pairing_repeated{
    my ($ARGV) = @_; #array reference
   
    my @pairing_list=();
    do_pairing($ARGV, \@pairing_list);
    print_pairing(\@pairing_list);
    save('file_example.txt', \@pairing_list);
}

# Run pairing NO repeated
sub do_pairing_no_repeated{
    my ($ARGV) = @_; #array reference
    my $no_repeated=1;
    my @pairing_list;
    do{
        @pairing_list=();
        do_pairing($ARGV, \@pairing_list);
        $no_repeated = compare_if_no_repeated($ARGV, \@pairing_list);
    } until($no_repeated);
    print_pairing(\@pairing_list);
    save('file_example.txt', \@pairing_list);
}

# Checks if couples are repeated in the two arrays
sub compare_if_no_repeated{
    my ($origin_list, $pairing_list) = @_; #array reference
   
    for(my $i=0; $i<=scalar @{$origin_list} - 1; $i = $i + 2){
       
        if ($i < scalar @{$origin_list} - 1) {
            if (are_repeated(@{$origin_list}[$i], @{$origin_list}[$i + 1], @{$pairing_list}[$i], @{$pairing_list}[$i + 1])){
                return 0;
                }
           
            }
    }    
    return 1;
}

# Checks if the two pairs are the same (repeated pairs)
sub are_repeated{
    my ($pair_1_a, $pair_1_b, $pair_2_a, $pair_2_b) = @_;
   
    if (($pair_1_a eq $pair_2_a) && ($pair_1_b eq $pair_2_b)){
        return 1
        }
    if (($pair_1_a eq $pair_2_b) && ($pair_1_b eq $pair_2_a)){
        return 1
        }
    return 0;
}

# Print pairing names from a members array
sub print_pairing{
    my ($members) = @_; #array reference
   
    for(my $index=0; $index<=scalar @{$members} - 1; $index = $index + 2){
        print @{$members}[$index] . "-";
        if ($index < scalar @{$members} - 1) {
            print @{$members}[$index + 1] . "\n";
            }else{
                print "none \n";
                }
    }    
}

# Run pairing
sub do_pairing{
    my ($members, $pairing_list) = @_; #array reference

    my @members_copy;
   
    foreach my $elem (@{$members}) {
        push (@members_copy, $elem);
    }
   
    my $members_count = scalar @members_copy;
    do{
        my $selected =  get_member_and_remove_it_random(\@members_copy);
        $members_count = $members_count - 1;
        push (@{$pairing_list}, $selected);
       
    } until($members_count==0);
}

# Retrieves a member and removes it from the array.
sub get_member_and_remove_it_random{
    my ($members) = @_; #array reference
    my $size = scalar @{$members};
    my $random_number = int(rand($size));
    my $removed_member =  splice @{$members}, $random_number, 1;
    return $removed_member;
}

sub read_array_from_file{
    my ($filename) = @_;
    my @input_array = ();

    if (open(my $fh, '<:encoding(UTF-8)', $filename)) {
        while (my $row = <$fh>) {
            chomp $row;
            push (@input_array, $row);
        }
    } else {
        warn "Could not open file '$filename' $!";
        }
    return \@input_array;
}

sub save{
    my ($filename, $array_reference) = @_;
   
    open(my $fh, '>:encoding(UTF-8)', $filename) or die "Could not open file '$filename' $!";
   
    foreach my $elem (@{$array_reference}) {
        print $fh "$elem\n";
    }

    close $fh;
}

miércoles, 9 de septiembre de 2015

Perl: Pairing in Pair programming

Script para formar parejas para programación de a pares


#!/usr/bin/perl -s
# File: pairing.pl 
# Perl Scrip to Pairing in Pair programming
# Command line example:
# perl pairing.pl "Dario" "Karina" "Claudia" "Pancho"

  
use strict;
use warnings;

# Begin main
# @ARGV is a array of command line arguments
if (scalar @ARGV > 0){
    runPairing(\@ARGV);
}else{
    print "No arguments. Enter names. For example: \n";
    print "perl pairing.pl \"name1\" \"name2\" \"name3\" \"name4\" \n";
    }

# End main


# Run pairing
sub runPairing{
    my ($members) = @_; #array reference
    my $members_count = scalar @{$members};
    my $pair_count = 1;
    do{
        my $first_selected =  getMemberAndRemoveItRandom($members);
        $members_count = $members_count - 1;
        if ($members_count > 0){
            my $second_selected =  getMemberAndRemoveItRandom($members);
            $members_count = $members_count - 1;
            print "Pair $pair_count: " . $first_selected;
            print " - " . $second_selected . " \n";
            }else{
                print "Pair $pair_count: " . $first_selected . " - none\n";
                }
        $pair_count = $pair_count + 1;
    } until($members_count==0);
}

# Retrieves a member and removes it from the array.
sub getMemberAndRemoveItRandom{
    my ($members) = @_; #array reference
    my $size = scalar @{$members};
    my $random_number = int(rand($size));
    my $removed_member =  splice @{$members}, $random_number, 1;
    return $removed_member;
}



viernes, 24 de julio de 2015

SVN: Ancestrally problem or How to copy branch to trunk


Cómo solucionar el problema de tratar de generar el trunk cuando se partó a trabajar en una rama directamente y no desde el trunk.

PROBLEMA:


Se intenta mergear desde una rama (el código del proyecto está en una rama) cuando el trunk está vacío y el proyectos se creó desde la rama y no desde el trunk.

svn merge ^/branches/MyBranch/ --reintegrate
svn: 'https://svn.example.com/repos/MyRepo/branches/MyBranch@92' must be ancestrally related to 'https://svn.dev.example.com/repos/MyRepo/trunk@92'
dario.palminio@exampleglb-l1077:~/Workspace/reissuePrice_trunk$ svn merge ^/branches/MyBranch/
--- Merging r11 through r92 into '.':
   C doc
   C src
   C pom.xml
 U   .
Summary of conflicts:
  Tree conflicts: 3
dario.palminio@exampleglb-l1077:~/Workspace/reissuePrice_trunk$ ll


SOLUCIÓN:


Una solución es regenerar el trunk (que actualmente está vacío):

svn delete -m 'Borra el trunk para regenerarlo' https://svn.example.com/repos/MyRepo/trunk

svn copy -m 'Genera el trunk copiando desde el branche 1260' https://svn.example.com/repos/MyRepo/MyBranch https://svn.example.com/repos/MyRepo/trunk

Esto debería funcionar, pero si tira un error como el que sigue:
...svn: Path 'https://svn.example.com/repos/MyRepo/MyBranch' does not exist in revision 93

Se puede probar copiar la copia local al trunk (regenerándolo):

svn copy . https://svn.example.com/repos/MyRepo/trunk



domingo, 5 de julio de 2015

SCRUM: Agile viewpoint

En SCRUM desde el punto de vista de la agilidad, entre otras cosas, tenemos en cuenta lo siguiente:

"
1) Evitamos el BDUF (Big Design Up Front) porque asumimos que el contexto es cambiante. Por lo tanto, al anticiparnos mucho, generamos desperdicio de trabajo y re-trabajo por tener supuestos equivocados.

2) Damos prioridades a los ítems del Backlog porque sabemos que gran parte de todos las características de un producto terminan utilizándose poco o nada.

3) Refinamos y destilamos el Backlog constantemente para hacer frente a los cambios de contexto y necesidades de nuestros clientes.

4) Tenemos revisiones frecuentes para minimizar el stock de requerimientos sin validar.

5) Ponemos el foco en maximizar el retorno de la inversión y no solo en la reducción de costos.

6) Buscamos maximizar el flujo de trabajo, aunque debamos reducir la cantidad de trabajo en progreso., porque sabemos que así mejoramos el ritmo y el time-to-market o lead/cycle time.

" (Martín Alaimo, 2015)

miércoles, 20 de mayo de 2015

Development tool: sniff de tráfico

httpry


La tool "httpry" es una herramienta para hacer sniff de tráfico en Linux (Ubuntu) web HTTP (i.e., HTTP requests and responses) o analizar paquetes (packet analyzer) en comunicaciones por interface. Es una alternativa simple de wireshark útil para analizar comunicaciones HTTP, REST y SOAP.

Instalación:


sudo apt-get install git
sudo apt-get install gcc make libpcap0.8-dev
git clone https://github.com/jbittel/httpry.git
cd httpry
make
sudo make install
httpry -h

Usar interface Ethernet:

sudo httpry -i et0

#Todos paquetes tcp por ethernet
sudo httpry -i eth0 'tcp'

Usar interface localhost:

sudo httpry -i lo

#Todos paquetes tcp de todos los puertos de localhost
sudo httpry -i lo 'tcp'

#Para diferentes puertos específicos a la vez
sudo httpry -i lo 'tcp port 80 or 8080 or 8090'

#Uso de expression specify a bpf-style capture filter para muchos puertos
sudo httpry -i lo 'tcp port 80 or 8080 or 8280 or 8290 or 8230 or 8140 or 8320 or 8310 or 8150 or 3307 or 8090'

Usar interface Wireless

sudo httpry -i wlan0 -o dump.txt

Arrojar a un archivo

sudo httpry -i lo -o dump.txt
sudo httpry -i wlan0 -o dump.txt

Ejemplo de una salida

Copyright (c) 2005-2014 Jason Bittel <jason.bittel@gmail.com>
Starting capture on lo interface
2015-05-20 18:05:33.689 127.0.0.1 127.0.0.1 > POST localhost:8080 /Service/soap/srv1 HTTP/1.1 - -
2015-05-20 18:05:33.759 127.0.0.1 127.0.0.1 > POST localhost:8080 /Service/soap/srv2 HTTP/1.1 - -
2015-05-20 18:05:33.785 127.0.0.1 127.0.0.1 > POST localhost:8230 /Service/1.0/soap/srv3 HTTP/1.1 - -
2015-05-20 18:05:34.294 127.0.0.1 127.0.0.1 < - - - HTTP/1.1 200 OK
2015-05-20 18:05:36.026 127.0.0.1 127.0.0.1 > POST localhost:8230 /Service/1.0/soap/srv4 HTTP/1.1 - -
2015-05-20 18:05:36.349 127.0.0.1 127.0.0.1 < - - - HTTP/1.1 200 OK
2015-05-20 18:05:36.355 127.0.0.1 127.0.0.1 < - - - HTTP/1.1 200 OK
2015-05-20 18:05:36.370 127.0.0.1 127.0.0.1 > POST localhost:8230 /Service/1.0/soap/srv5 HTTP/1.1 - -
2015-05-20 18:05:36.700 127.0.0.1 127.0.0.1 < - - - HTTP/1.1 200 OK
2015-05-20 18:05:37.166 127.0.0.1 127.0.0.1 > POST localhost:8090 /Service/1.0/soap/srv6 HTTP/1.1 - -
2015-05-20 18:05:37.573 127.0.0.1 127.0.0.1 < - - - HTTP/1.1 500 Internal Server Error
2015-05-20 18:05:37.584 127.0.0.1 127.0.0.1 > POST localhost:8230 /Service/1.0/soap/srv4 HTTP/1.1 - -
2015-05-20 18:05:37.908 127.0.0.1 127.0.0.1 < - - - HTTP/1.1 200 OK
2015-05-20 18:05:37.918 127.0.0.1 127.0.0.1 < - - - HTTP/1.1 200 OK
...

Filtrar por tipo de HTTP 

Filtrar por GET, POST, PUT, HEAD, CONNECT, etc…:

sudo httpry -i wlan0 -m get,post,head



Referencias:
http://xmodulo.com/sniff-http-traffic-command-line-linux.html
http://manpages.ubuntu.com/manpages/saucy/man1/httpry.1.html
http://dumpsterventures.com/jason/httpry/


Metodología Ágil: Qué es una Story y qué no



Criterio de demarcación de una Story

¿Qué es una Story y qué no? ¿Cuál es el criterio de demarcación?


¿Qué es una Story?


Según el concepto general de metodología Ágil, la Story se define como una "promesa de una conversación " o una "descripción de una característica" [UNTREF 2014] [Dan North 2015]. Según esta perspectiva, representa una "funcionalidad de aplicación" para un usuario y que brinda un beneficio (ROL + FUNCIONALIDAD + BENEFICIO):

COMO <ROL> QUIERO <FUNCIONALIDAD> PARA QUE <BENEFICIO>

No es exactamemte un requerimiento pero puede considerarse como el título de un requerimiento como recordatorio de algo relevante a conversar con el usuario (o cliente). En consecuencia lo relevante es su evolución como conversación [UNTREF 2014].

La Story describe lo que el usuario quiere hacer desde la perspectiva de una interacción con un proceso de negocio, describe el objetivo del usuario en términos de necesidad de obtener algo que se hace en el negocio [Bellware Scott 2014].

Según Dan North y en el marco de Behavior-Driven Development (BDD), una Story es más un requerimiento, pues tiene que ser una descripción de un requisito y su beneficio para el negocio, y un conjunto de criterios con los que todos estamos de acuerdo de qué es o lo que se hace, "lo que el cliente necesita" [Dan North 2015]


Story para Scrum


Para Scrum existen items de Backlog de producto PBI que se los suele denominar como Story. El Product Backlog incluye incisos o Stories que aportan valor al cliente y que suelen ser descripción de requisitos funcionales. Aunque también puede incluir entradas para exploración de características, necesidades del cliente u opciones técnicas, requerimientos no funcionales, el trabajo necesario para lanzar el producto, y otros incisos, así como la configuración del entorno o arreglar defectos [Scrum-Institute , 2015]. O sea que puede proporcionar valor en forma indirecta mediante el aumento de la calidad o la reducción de los incidentes en el largo plazo [Scrum-Institute , 2015].

¿Cuál es el criterio de demarcación?


El criterio de demarcación aceptado en metodología ágil en general es el criterio INVEST que consta de seis características a cumplir:

1- Independiente: debe ser atómica.
2- Negociable: debe ser conversable y en consecuencia negociable (es viva).
3- Valueble: debe generar un valor al usuario o cliente. Una Story sin una declaración de la motivación del usuario a menudo se piensa que es no accionable; es decir, la historia no se puede estimar o implementar fácilmente [Bellware Scott 2014].
4- Estimable: se debe poder estimar.
5- Pequeña: debe ser lo suficientemente pequeña para entrar en un sprint o iteración.
6-  Probable: debe poder ser testeable.


[UNTREF 2014][Agile Alliance 2015] (Bill Wake's)


¿Qué NO es una Story?


Si no cumple con el criterio INVEST es bastante probable que no sea una Story. Por ejemplo una tarea puramente técnica (que le interesa solo al desarrollador), un refactoring técnico o un Spike no cumplen con INVEST y en su generalidad no son Story. Veamos:


Spike: 


No es una Story ya que es una tarea de investigación y/o experimentación en formato time-boxing por lo que no cumple con ser testeable ni estimable (no cumple con dos criterios).


Refactoring Task: 


Es una tarea técnica que no es valuable o su valoración es a futuro o en relación a un atributo de calidad que puede no estar directamente solicitado por el cliente o no impacta en beneficio inmediato para el cliente, ya que podría estar resolviendo una deuda técnica. Esto no quiere decir que no pueda haber una "story de refactoring" que puede proporcionar valor en forma indirecta mediante el "aumento de la calidad o la reducción de los incidentes en el largo plazo".



Technical Story:


“Cada historia tiene que ser valorado por los usuarios. Pero eso sería un error." [Mike Cohn 2004] Pues en realidad, una historia de usuario describe la funcionalidad que será valiosa para un usuario o comprador de un sistema o software [Mike Cohn 2004]. Hay historias que especifican aspectos técnicos que no son valiosos para el usuario sino mas bien para el cliente o comprador (la valoración es transitiva y no directa). Historias técnicas pueden ser valorados por los compradores que contemplan la compra del producto, pero no serían valorados por los usuarios reales. Pero esto no es lo que podemos llamar una "Technical Story" sino que es una Story con aspectos técnicos que tiene valor para el cliente. Para Scott Ambler en Agile Modeling, una Story es una definición de muy alto nivel de un requerimiento que puede ser funcional o no, por ejemplo de un requerimiento técnico [Scott Ambler 2015], por ejemplo: "como usuario quiero que las transcripciones estén disponibles en línea a través de un navegador estándar lo que me permite acceder desde cualquier lugar" [Scott Ambler 2015].

Cuando se habla de "Technical Story" se referencia a aquella historia técnica que sólo es valorada por los desarrolladores. Estas historias son las que se quieren evitar y considerar como Technical Story que podría ser una tarea técnica o una historia mejor redactada. Este tipo de historias se centran en la tecnología y las ventajas para los programadores. Es muy posible que las ideas detrás de estas historias sean buenas, pero en cambio deben ser escritas para que los beneficios a los clientes o usuarios sean evidentes. Esto permitirá que el cliente priorizar inteligentemente estas historias en el calendario de desarrollo [Mike Cohn 2004].

Para la Agile Alliance una Story no se corresponden en general a un "componente técnico" o de la "interfaz de usuario", pues a pesar de que a veces puede ser un atajo útil hablar de por ejemplo "la historia de diálogo de búsqueda", pantallas, cuadros de diálogo y botones, no son historias de usuario [Agile Alliance 2015].


Referencias:

[Mike Cohn 2004]
User Stories Applied For Agile Software Development. Mike Cohn, 2004.

[Dan North 2015]
WHAT’S IN A STORY? Dan North, 2015.

[UNTREF 2014]
Construcción de software: una mirada ágil. Nicolás Paez, Diego Fontdevila, Pablo Suárez, Carlos Fontela, Marcio Degiovannini, Alejandro Molina. Universidad Nacional de Tres de Febrero (UNTREF), 2014.

[Bellware Scott 2014]
Behavior­Driven Development. By Bellware Scott. Code Magazine, by EPS Software Corp. 1993 ­ 2014. All rights reserved. (www.codemag.com/article/0805061)

[Scott Ambler 2015]
User Stories: An Agile Introduction. Scott Ambler and Associates, Agile Modeling, 2015. URL: http://www.agilemodeling.com/artifacts/userStory.htm

[Agile Alliance 2015]
Agile Alliance, User Stories. URL: http://guide.agilealliance.org/guide/user-stories.html


[Scrum-Institute , 2015]
Scrum revealed: the only book can simply learn scrum! International Scrum Institute (scrum-institute.org) o ISI.

lunes, 18 de mayo de 2015

Metodología Ágil: Documentación Arquitectónica y Diseño.

Metodología Ágil: Documentación Arquitectónica y Diseño.

Hay algunas preguntas que se plantean (en desarrollo de software) en lo referente a la Arquitectura y el Diseño de software en la filosofía ágil tales como: ¿Es necesaria alguna documentación de arquitectura trabajando con metodologías Ágiles? ¿Es necesario el diseño trabajando con metodologías Ágiles?
Hay quienes contestan (en un marco de agilidad) que no, no es necesario: el código es el diseño.

El código es el diseño


Existe una idea, en la agilidad de software, de diseño minimalista y evolutivo que dice que “el código fuente es el diseño” [Reeves 1992][Ruth & Bredemeyer 2002]; y según esta idea (en extremo) se puede ver al código fuente como el resultado final y visible del diseño, y en dónde quedan plasmados todos los aspectos de éste (no es necesario nada más). Esta idea es llevada al extremo con algunos practicantes de algunas metodologías ágiles, en donde se considera que el diseño no existe como etapa de desarrollo ni como generador de algún artefacto formal y tampoco hay alguna documentación que esboce la arquitectura del sistema. Sólo se tiene en cuenta el diseño como algo informal, útil para transmitir ideas entre desarrolladores. La justificación es que es engorroso mantener documentación y que con el refactoring continuo, el buen diseño se va encontrando de a poco en forma emergente. También hay una mala interpretación de: "Software funcionando sobre documentación extensiva" [Manifiesto Ágil]. Priorizar el producto en lugar de la "documentación extensiva" no implica eliminar la documentación.

El código NO es el diseño


La crítica a lo anterior es que "el código no es el diseño". Esta difundida una creencia errónea de que la agilidad implica no documentar [UNTREF 2014]. La idea de que en el código se refleja toda decisión de diseño [UNTREF 2014]. Pues no, eel código no es el diseño, porque solamente nos muestra una vista de éste (la vista de código), mientras también existe, entre otras, la dinámica y la integración. También hay varios modelos, por ejemplo: el de componentes, el de análisis, el de casos de uso, etc. Decir que el código fuente es el diseño es como decir que el edificio terminado es su diseño [Anacleto 2005] y no es necesario nada más para entenderlo. Con solo el código podemos ver la estructura interna del código y extraer información, pero no podemos ver la estructura interna de los componentes que usa, así como tampoco nos es práctico extraer información a partir de la estructura, entender la integración, la dinámica de componentes, la justificación de su estructura y el funcionamiento del todo. La abstracción es necesaria para comprender el todo paulatinamente y de manera efectiva. No significa mantener alto formalismo en la especificación, no significa mantener grandes y engorrosos documentos, no significa planificar y preveer todo el diseño en forma previa; sino que significa no carecer de alguna documentación de arquitectura de sistemas, no prescindir de hacer arquitectura y diseño; tener la documentación minima y necesaria para entender la arquitectura del sistema de forma ágil (y no perder tiempo enorme de investigación haciendo ingeniería inversa para entender el sistema); significa plasmar los lineamientos arquitectónicos durante todo el desarrollo para posibilitar la emergencia de una buena arquitectura; y significa hacer ingeniería. El buen diseño NO surge necesariamente de un grupo de personas trabajando o haciendo artesanía. El buen diseño SI emerge del trabajo en equipo de profesionales motivados altamente capacitados haciendo ingeniería.

Por otro lado, se puede argumentar que el código es un nivel intermedio de abstracción y modelado y el de arquitectura o diseño arquitectónico es superior en niveles de diseño de software. Por lo que solo con el código no alcanza para modelar el sistema y entenderlo. Shaw and Garlan [Shaw 1996] proponen tres niveles de modelado y comprención: Máquina, Código y Arquitectura [Malveau 2004]. Según estos niveles: "el código no es el diseño".

Documentar en forma Ágil


La agilidad implica un balance intermedio:
"ni el extremo de plasmar todas las decisiones en documentos, ni el otro de creer que el código puede mantener toda la información necesaria[UNTREF 2014].
El diseño y su documentación debe permitir la colaboración, el refactoring (con documentos vivos) y la simplicidad (documentos minimalistas y eficaces en didáctica) entre otras características. Se debería poder plasmar la justificación de por qué se tomaron siertas decisiones ya sea en documentos o en comentarios en el código.

El nacimiento del documento de arquitectura, en metodologías ágiles, puede ser al inicio de las iteraciones o al de una épica. En metodología XP se usa el "Spike de Arquitectura" que genera la "Metáfora del sistema" como input de la etapa de "planificación de versiones". Esta "Metáfora del sistema" irá evolucionando en los sucesivas iteraciones. En Scrum se puede hacer algo semejante, se puede tener un sprint 0 para generar o modificar esta "Metáfora del sistema" que luego se irá modificando en los restantes sprints. También el documento puede surgir o ser modificado en stories técnicas de investigación o específicas de diseño.

Documentación Arquitectónica


Lo ideal de una documentación arquitectónica (Documento de Arquitectura de Software SAD) es que sea minimalista, didáctica, versionable (el SAD es un documento vivo [DSA 2010]), accesible e indexada a un código específico (o revisión de código fuente). En este sentido se pueden realizar diferentes implementaciones. 


Documentación con LaTeX


Particularmente me inclino por que haya una documentación versionable básica en el mismo lugar donde se encuentra el código. Por ejemplo en una carpeta "doc". Para que sea versionable se puede usar código html o LaTeX. Algunos pueden decir que es dificil que todos sepan html o LaTeX para editar un documento, pero no es necesario que todos sepan, con que sepan los arquitectos y/o desarrolladores alcanza, Y los mismos son ingenieros y técnicos que deberían estar capacitados para que la edición de un html o LaTex sea algo trivial.
Se puede tener alguna plantilla básica o "documento base" [DSA 2010] de un SAD base y trabajar sobre él. Por ejemplo aquí hay tres documentos base:



     (Repositorio GIT: https://github.com/dariopalminio/latex.templates)

Por convensión sería más apropiado que los documentos esten en ingles, para que sean didácticos puede llevar a escribir simple y claro; pero también se podría preferir la documentación en español (principalmente si los stakeholders que tiene acceso a su lectura son españoles).


Referencias:

[Ruth & Bredemeyer 2002] Malan, Ruth, and Dana Bredemeyer, "Less is More with Minimalist Architecture", published in IEEE's IT Professional, September/October 2002.

[Reeves 1992] Code as Desgin, Jack W. Reeves, 1992 Disponible en URL: http://www.developerdotstar.com/mag/articles/reeves_design_main.html

[Anacleto 2005] El rol de la arquitectura de software en las metodologías ágiles. Lic. Valerio Adrián Anacleto. Epidata Consulting S.R.L.- Buenos Aires, Argentina. Diciembre de 2005. Disponible en URL: http://www.epidataconsulting.com/tikiwiki/tiki-read_article.php?articleId=28#El_c_digo_NO_es_el_dise_o

[DSA 2010]
Documenting Software Architectures: Views and Beyond. Paul Clements (Author), Felix Bachmann  (Author), Len Bass (Author), David Garlan (Author), James Ivers (Author), Reed Little (Author), & 3 more. October 15, 2010.
https://connectopensource.atlassian.net/wiki/pages/viewpage.action?pageId=10584112
https://wiki.sei.cmu.edu/sad/index.php/Software_Architecture_Documentation_Template


[UNTREF 2014]
Construcción de software: una mirada ágil. Nicolás Paez, Diego Fontdevila, Pablo Suárez, Carlos Fontela, Marcio Degiovannini, Alejandro Molina. Universidad Nacional de Tres de Febrero (UNTREF), 2014.

[Simon Brown 2915]

Simple Sketches for Diagramming your Software Architecture
Disponible en URL: http://www.methodsandtools.com/archive/softwarearchitecturesketches.php

[Adrián Paredes 2012]
Documento de Arquitectura de Software. 2012.
Disponible en URL: http://elblogdelfrasco.blogspot.com.ar/2012/02/documento-de-arquitectura-de-software.html

[Manifiesto Ágil]
Manifiesto por el Desarrollo Ágil de Software. URL: http://agilemanifesto.org/iso/es/


[Malveau 2004]
Software Architect BOOTCAMP. The completely updated “field manual” for becoming a better software architect! Raphael Malveau, Thomas J. Mowbray Ph.D. Prentice All, Second Edition, 2004 Pearson Education Inc.ISBN: 0-13-141227-2. Disponible en URL: http://users.atw.hu/softarchcamp/



martes, 31 de marzo de 2015

SVN: How to revert last change on a file?

¿Cómo revertir el último cambio en solo un archivo con SVN?

¿Cuál es la mejor manera de volver a una revisión anterior de un solo archivo en SVN?

svn log -l 2
------------------------------------------------------------------------
r537635 | coco | 2015-03-30 20:58:55 +0000 (Mon, 30 Mar 2015) | 1 line

[Ticket]: Fix bug
------------------------------------------------------------------------
r536022 | coco | 2015-02-20 20:33:51 +0000 (Fri, 20 Feb 2015) | 70 lines

svn merge -c -537635 t/unit/test_01.t

svn merge -c -537635 t/unit/test_01.t
--- Reverse-merging r537635 into 't/unit/test_01.t':
U    t/unit/test_01.t
--- Recording mergeinfo for reverse merge of r537635 into 't/unit/test_01.t':
 G   t/unit/test_01.t
--- Eliding mergeinfo from 't/unit/test_01.t':
 U   t/unit/test_01.t

svn commit -m "[Ticket]: REVERT cambios en unit test"


svn up --ignore-externals
svn log -l 2

------------------------------------------------------------------------
r537657 | coco | 2015-03-31 14:02:24 +0000 (Tue, 31 Mar 2015) | 1 line

[Ticket]: REVERT ultimo cambio en unit test
------------------------------------------------------------------------
r537635 | coco | 2015-03-30 20:58:55 +0000 (Mon, 30 Mar 2015) | 1 line

[Ticket]: Fix bug
------------------------------------------------------------------------



Referencias:

domingo, 1 de marzo de 2015

Java: How to use Generic Types to create a generics class

Java: How to use Generic Types to create a generics class


A generic type is a generic class or interface that is parameterized over types.

Las clases genéricas (con tipos genéricos) permiten, entre otras cosas, forzar la seguridad de los tipos creados por nosostros, en tiempo de compilación. También permiten abstraer comportamiento independientemente de tipo de objeto que se manipule.

Esto se puede apreciar con un ejemplo:

Example diagram




Example code


//........................................................
//File name: IMyGenericClass.java

package com.daro.generic.example.generic;

import java.util.List;

public interface IMyGenericClass<T> {

public void printClassName(T p);
public List<T> list(Class<T> clazz);

}

//........................................................
//File name: MyGenericClass.java

package com.daro.generic.example.generic;

import com.daro.generic.example.generic.IMyGenericClass;
import java.util.ArrayList;
import java.util.List;

public abstract class MyGenericClass<T> 
                implements IMyGenericClass<T> {

private final Class<T> type; public MyGenericClass(Class<T> type) { this.type = type; } public Class<T> getMyType() { return this.type; }

@Override
public void printClassName(T p) {
System.out.println ("Class name: " + p.getClass().getName());
}

@SuppressWarnings("unchecked")
@Override
public List<T> list(Class<T> clazz) {
@SuppressWarnings("rawtypes")
Object object = null;
try {
object = clazz.newInstance(); 
                         //equal to this.getMyType().newInstance()
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
List<T> list = new ArrayList<T>();
list.add((T)object);
return list;
}

}

//........................................................
//File name: MyGenericClassImpl.java

package com.daro.generic.example.generic;

import java.util.List;
import com.daro.generic.example.generic.MyGenericClass;
import com.daro.generic.example.generic.MyClass;


public class MyGenericClassImpl extends MyGenericClass<MyClass> {

public MyGenericClassImpl() {
super(MyClass.class);
}

public void doSomething() {
   MyClass myClass = new MyClass();
List<MyClass> myList = this.list(MyClass.class);
this.printClassName(myClass);
System.out.println("To string my object: " + myList.get(0).toString()); 
}
   
public static void main(String[] args) {
        System.out.println("Running test!"); // Display the string.
MyGenericClassImpl myGenericClassImpl = new MyGenericClassImpl();
myGenericClassImpl.doSomething();
}

}

//........................................................
//File name: MyClass.java

package com.daro.generic.example.generic;

import java.io.Serializable;

public class MyClass {

public String toString(){
return "MyClass Example";
}

}


Running Example


Result of run MyGenericClassImpl:

Running test!
Class name: com.daro.generic.example.generic.MyClass

To string my object: MyClass Example



References:

http://docs.oracle.com/javase/tutorial/java/generics/types.html
http://www.arquitecturajava.com/uso-de-java-generics/
http://jonsegador.com/2012/10/clases-y-tipos-genericos-en-java/




martes, 24 de febrero de 2015

Perl: Constants

Constantes en Perl y Moose


Ejemplo de como usar constantes en Perl usando Moose


{
    package Parent;
    use Moose;
    use namespace::autoclean;

    use constant MY_CONSTANT => 'CONSTANT';

    use constant {
        MY_CONSTANT => 'CONSTANT'
        NO_LEVEL => 0,
        MY_LEVEL => 1,
    };

    sub printMyConstant {
        my $self = shift;
        print &MY_CONSTANT;
    }


    __PACKAGE__->meta->make_immutable;
};

{
    package Child;
    use Moose;
    use namespace::autoclean;

    extends 'Parent';

    sub printMyLevel {
        my $self = shift;
        my $class = ref $self;

        print $class->MY_LEVEL;
        print &Parent::MY_CONSTANT;
    }
    __PACKAGE__->meta->make_immutable;
}

package main;

my $child = Child->new;
$child->printMyLevel;



miércoles, 18 de febrero de 2015

Perl: Using Maybe attribute not die on undef

Perl: Moose, Using Maybe attribute not die on undef


Problema


Cuando definimos atributos en Moose con constraint en tiempo de ejecución podemos encontrarnos con el siguiente tipo de excepciones: "Attribute (AttributeName) does not pass the type constraint because: Validation failed for 'Str' with value undef"
Para evitarlo podemos usar "Maybe". A continuación un ejemplo:

Class to Test


package ClassWithMaybe;

use Moose;

has 'atributoSinConstraints' => ( 
                is => 'rw', 
                isa => 'Maybe[Str]', 
                default => '',
                reader => 'getAtributoSinConstraints',
                writer => 'setAtributoSinConstraints'
                ); # will NOT die on undef

has 'atributoConConstraints' => (
                is => 'rw', 
                isa => 'Str',
                reader => 'getAtributoConConstraints',
                writer => 'setAtributoConConstraints'
                ); # will die on undef (esto puede generar la exception mostrada anteriormente)
    
sub BUILD {
    my $self = shift;
    $self->setAtributoSinConstraints('') unless defined $self->getAtributoSinConstraints;
}

no Moose; __PACKAGE__->meta->make_immutable;

TEST


package ClassWithMaybeTest;

use Moose;
use Test::More;
use Test::Exception; #cpanm Test::Exception
use ClassWithMaybe;

throws_ok { ClassWithMaybe->new( atributoConConstraints => undef ) }
    qr/Validation failed for 'Str' with value undef/; # will die on undef
    
lives_ok  { ClassWithMaybe->new( atributoConConstraints => "with data" ) } 
    'atributoConConstraints with data ok';

lives_ok  { ClassWithMaybe->new( atributoSinConstraints => undef ) } 
    'atributoSinConstraints supplied as undef'; # will not die on undef

my $classWithMaybe = ClassWithMaybe->new( atributoSinConstraints => undef , atributoConConstraints => "with data");

is $classWithMaybe->getAtributoSinConstraints, '', "atributoSinConstraints is ''";

$classWithMaybe = ClassWithMaybe->new();
$classWithMaybe->setAtributoSinConstraints(undef);# will not die on undef

is $classWithMaybe->getAtributoSinConstraints, undef, "atributoSinConstraints is undef";

done_testing;

Run test


perl ClassWithMaybeTest.t
ok 1 - threw Regexp ((?^:Validation failed for 'Str' with value undef))
ok 2 - atributoConConstraints with data ok
ok 3 - atributoSinConstraints supplied as undef
ok 4 - atributoSinConstraints is ''
ok 5 - atributoSinConstraints is undef
1..5


References: