Lean Software Development

Posted: Abril 16th, 2009 | Author: Jose Raya | Filed under: agilogy | Comentarios desactivados

Ya hace tiempo que quiero escribir sobre el libro Lean Software Development: An Agile Toolkit ya que lleva a cabo una tarea que me parece fundamental: Explicar cómo trasladar buenas prácticas de ingeniería (la parte lean) al desarrollo de software y lo hace, además, proponiendo las metodologías ágiles como resultado. ¿Qué más se puede pedir?

Aunque espero poder profundizar más en futuros posts, podríamos resumir la filosofía lean según los siete principios que nos proponen los Poppendieck:

  1. Evitar despilfarro (eliminate waste)
  2. Amplificar el aprendizaje (amplify learning)
  3. Decidir lo más tarde posible (decide as late as possible)
  4. Entregar lo antes posible (deliver as fast as posible)
  5. Dar poder al equipo (empower the team)
  6. Incluir la integridad de entrada (build integrity in)
  7. Tener una visión global (see the whole )

La verdad es que, visto así, resulta difícil no estar de acuerdo con los principios lean. Otra cosa es estar de acuerdo o no en la interpretación de los mismos y en su aplicación al desarrollo de software. Aunque pienso que las metodologías ágiles no son la única traslación posible de los principios lean al desarrollo de software (por ejemplo, dependerá de lo que entendamos por desperdicio) sí pienso que son la traslación más natural, lo cual explicaría por qué lean y agile son dos términos que, últimamente, se suelen ver emparejados.

En mi opinión, uno de los grandes aciertos del libro de los Poppendieck consiste en no trasladar tal cual el Toyota Production System al campo del software sino abstraer los principios básicos del mismo y trasladarlos teniendo en cuenta que no se trata de un proceso de manufactura sino de desarrollo. Por ejemplo, el desarrollo secuencial puede ser necesario en una cadena de montaje donde los componentes tienen que montarse en un orden determinado pero no lo es tanto en el desarrollo de software donde los distintos requisitos pueden trabajarse fácilmente en paralelo.

En conclusión, un libro muy interesante y altamente recomendado para cualquiera que desarrolle su actividad profesional en el campo del desarrollo de software.

Actualización: He añadido un enlace a la entrada donde hablo del primer principio Lean, “evitar el despilfarro”.


Quan evitar l’acoblament

Posted: Abril 16th, 2009 | Author: Jose Raya | Filed under: agilogy | Comentarios desactivados

“Acoblament baix” és un dels principis de disseny de software més àmpliament acceptats (de fet, no crec que poguem trobar cap referència enlloc on algú indiqui que és bó mantenir l’acoblament alt) però si apliquem aquest principi sense cap altre criteri, ens podem trobar [LAR] amb un disseny molt pobre on alguns objectes només actuin com a contenidors de dades (i no tinguin cap acoblament amb altres classes) mentre que altres concentrin tots els acoblaments i totes les responsabilitats del sistema. Per tant, i citant en Larman Some moderate degree of coupling between classes is normal and necessary for creating an object-oriented system in which tasks are fulfilled by a collaboration between connected objects.

Un cop acceptem que és necessari assumir un cert grau d’acoblament al sistema, necessitem establir criteris per a decidir, entre dos acoblaments, quin és més greu per tal de mantenir un bon disseny. El propi Larman ens ofereix algunes pistes a la discussió del patró GRASP: Hem d’evitar l’acoblament cap als elements menys estables o amb més possibilitats d’evolucionar.

Però en Larman no és l’únic autor que ha tractat aquest tema. D’altres, com ara en Robert C. Martin, l’han tractat des del punt de vista de la gestió de dependències. El principi d’inversió de dependències diu que:

  • a. Els elements d’alt nivell (d’abstracció) no haurien de dependre dels de baix nivell. Tots dos haurien de dependre d’abstraccions
  • b. Les abstraccions no haurien de dependre dels detalls. Els detalls haurien de dependre de les abstraccions

D’aquest principi podriem extreure un altre criteri: Evitar els acoblaments cap a elements de més baix nivell d’abstracció.

Finalment, una tercera variable que hem de tenir en compte és que el concepte d’acoblament depèn de quina sigui la unitat organitzativa que volguem tractar. Per exemple, podem considerar els acoblaments entre classes, entre paquets, mòduls o subsistemes. En Robert C. Martin [MAR] dedica un capítol sencer a la gestió de l’acoblament entre paquets, mentre que altres autors com en Bertrand Meyer [MEY] o en Martin Fowler també tracten el tema de l’acoblament associat al concepte de mòdul o subsistema. Per tant, és molt important gestionar l’acoblament a nivell de paquets.

Recapitulant, doncs, ens trobem amb tres variables o criteris per decidir: La possibilitat de canvis, el nivell d’abstracció i la pertanyença a un mateix paquet. En realitat, però, si hem fet una bona organització de paquets, totes les classes d’un mateix paquet tindran un mateix nivell d’abstracció i, a més, hauran previst el mateix tipus de canvi, de manera que, si hem fet una bona organització de paquets, el criteri principal és evitar els acoblaments cap a classes d’altres paquets, especialment si el seu nivell d’abstracció és més baix que el del paquet de la classe en qüestió ja que son les que ténen més possiblitats de treballar a un nivell d’abstracció diferent o de canviar per motius que poden no haver estat previstos al disseny de la nostra classe.

Significa això que la resta d’acoblaments no s’han d’evitar? Mai. Això només significa que, en termes generals, hem d’evitar, de manera preferent, els acoblaments cap a classes que pertanyin a altres paquets. Per exemple, és una mala decissió afegir un acoblament cap a una classe d’un altre paquet per evitar un acoblament cap a una classe del mateix paquet.

Referències:

[LAR] Craig Larman, Applying Uml and Patterns, 3rd Edition
[MAR] Robert C. Martin, Agile Software Development: Principles, Patterns and Practices
[MEY] Bertrand Meyer, Object Oriented Software Construction


Domain Model: Del disseny a la implementació persistent

Posted: Abril 16th, 2009 | Author: Jose Raya | Filed under: agilogy | Comentarios desactivados

A l’article Domain Model: De l’anàlisi al disseny hem parlat del patró de disseny Domain Model i de com arribar a un conjunt de classes software a partir d’un model conceptual d’anàlisi. El que ens proposem en aquest article és donar el següent pas cap a la implementació i tractar la problemàtica de com fer persistents les dades que conté aquest model. La solució proposada es basarà en la tecnologia JPA (Java Persistence API) que ens permet lligar aquest model del domini amb l’estructura de la base de dades relacional.

JPA defineix una família d’implementacions del patró Data Mapper que defineix en Martin Fowler, al seu llibre Patterns of Enterprise Application Architecture. Aquesta tecnologia assumeix que hi ha una base de dades relacional que té una certa similitud amb el model del domini ja que totes dues haurien de ser derivats d’un mateix model: El model conceptual del domini.
El nostre subsistema JPA (a l’article farem servir Hibernate com a referència) requereix que se li subministrin dades addicionals sobre com s’ha d’establir la correspondència entre el model del domini i el model físic de la base de dades. El principi d’inversió de dependències ens diu que hem d’implementar aquest model del domini sense dependre de detalls específics de la plataforma, per la qual cosa hauriem de subministrar aquestes metadades de manera independent del codi de les classes del model del domini (de fet, aquest és l’enfocament inicial de moltes eines de mapeig objecte-relacional i encara es pot fer servir amb JPA). A la pràctica, però, s’ha demostrat que el fet d’haver de mantenir dos fitxers diferents per a cada entitat, un fitxer java amb la classe que la implementa i un fitxer (típicament xml) de mapeig amb les dades de persistència i mantenir-los sincronitzats és també costós i propens a errors, per la qual cosa necessitem un enfocament mixte. Una de les grans novetats de JPA ha sigut, precissament, aportar aquest enfocament mixte gràcies a l’ús d’anotacions (novetat de Java 5). Aquesta solució, com qualsevol solució basada en anotacions, implica un cert acoblament del codi java cap les anotacions de JPA (és necessari JPA per compilar el codi) però permet l’execució del codi anotat en un entorn no-JPA.
Finalment, necessitem un punt d’entrada al subsistema JPA que permeti a les classes de la capa de domini recuperar instàncies d’objectes de la base de dades o actualitzar la base de dades amb les dades que tenim al model del domini. JPA ens ofereix la interfície EntityManager que ens dóna accés a aquest subsistema amb una interfície prou simplificada per executar consultes, recuperar instàncies a partir del seu identificador o actualitzar instàncies. Una opció que ens podem plantejar, doncs, és fer servir l’EntityManager des de les classes de la capa de domini; el principal problema d’aquesta opció és que, si apliquem el principi d’inversió de dependències , les classes de la capa de domini no haurien de dependre de l’EntityManager ja que aquest és menys abstracte i, per tant, hem d’introduir una abstracció intermitja: El controlador de dades o diccionari de dades. Aquesta interfície definirà les operacions que la capa de domini necessita de la capa de dades i la seva implementació farà d’adaptador entre aquesta interfície i la interfície oferta per l’EntityManager. A continuació es mostra un diagrama UML amb els elements que formarien part d’aquesta solució:
Adaptador de dades

Conclusions

S’ha proposat una solució que permet sincronitzar el model del domini amb el model persistent de les dades amb un cost de codificació mínim ja que només s’han de codificar les metadades de mapeig, les consultes que es considerin necessàries i els adaptadors de dades. A més, la solució proposada permet mantenir un compromís òptim entre independència entre el model del domini i el subsistema de persistència i facilitat de manteniment mitjançant l’ús d’anotacions.
No s’ha considerat a l’article com definir aquestes metadades de mapeig (es poden trobar a l’article Implementació de models conceptuals persistents amb Java i JPA ).


Implementació de models conceptuals persistents amb Java i JPA

Posted: Abril 16th, 2009 | Author: Jose Raya | Filed under: agilogy | Comentarios desactivados

En aquest article presentarem diversos exemples de com anotar una classe pertanyent al model del domini d’un sistema d’informació (veure Domain Model: De l’anàlisi al disseny i Domain Model: Del disseny a la implementació persistent) amb anotacions de JPA (Java Persistence API) per tal de mantenir sincronitzades les dades en memòria amb les dades existents a la base de dades. No és la meva intenció descriure en detall com funciona JPA sino, simplement, mostrar com es pot afegir les anotacions de JPA al model del domini per fer-lo persistent. Com a exemple, prendrem el model conceptual de la base de dades Northwind que es distribueix amb MSAccess i SQLServer.

Entitats del domini

El patró Domain Model ens diu que tota entitat del model conceptual tindrà una classe software (en el nostre cas, una classe java) que la representarà. Prenem com a exemple, l’entitat Employee:

public class Employee  implements java.io.Serializable {
...
}

JPA ens diu que, a cada classe del model del domini que representi una entitat, haurem d’afegir l’anotació @Entity per tal de poder-la reconèixer com a tal i @Table per tal de saber a quina taula es guardaran les dades d’aquella entitat:

@Entity
@Table(name="Employees",schema="dbo",catalog="Northwind")
public class Employee  implements java.io.Serializable {
...
}

JPA defineix una sèrie de valors per defecte per tal de minimitzar el volum de les anotacions. En el nostre cas, a l’anotació @Table hagués fet servir el nom de la classe com a nom de taula i l’esquema i catàleg per defecte de la base de dades.

Cada entitat tindrà una sèrie d’atributs, que es correspondran a les columnes de la base de dades i a les propietats de la classe java. Així doncs, Employee tindrà diversos atributs (employeeid, lastName, firstName, etc.). Per cada atribut hem de declarar un mètode getter per a obtenir el valor i un mètode setter per a modificar-lo. Típicament, la implementació d’aquests mètodes manipularà un atribut privat de l’objecte:

    private String city;
    ...
    @Column(name="City", length=15)
    public String getCity() {
        return this.city;
    }

    public void setCity(String city) {
        this.city = city;
    }

L’anotació @Column ens permet indicar amb més detall informació sobre la columna, concretament el nom. La regla per defecte (si no indiquem @Column) és mapejar la propietat a la columna amb el mateix nom. També es pot afegir informació addicional per a la generació de la definició de taules a partir de les classes i les metadades de mapeig.
Opcionalment, també podriem mapejar les columnes a partir dels atributs de la classe java enlloc de les propietats. Per a fer això, hauriem de posar les anotacions als atributs en comptes dels setters. Finalment, cal tenir en compte que tots els atributs de l’entitat s’han de mapejar o bé a propietats o bé a atributs (JPA decidirà on buscar l’anotació en funció d’on trobi l’anotació de l’identificador).

Identificadors i “ValueTypes”

L’identificador és la propietat que identifica un objecte (en terminologia de bases de dades, la clau primària). És una propietat especial ja que és la que permet al subsistema de persistència determinar si dues instàncies d’una classe representen o no la mateixa instància d’una entitat del domini (és a dir, si han d’anar a la mateixa fila de la taula). S’ha d’anotar amb l’anotació Id:

    ...
    @Id
    @Column(name="EmployeeID", unique=true, nullable=false)
    public int getEmployeeId() {
        return this.employeeId;
    }
    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }

En el cas de Hibernate, existeix la possibilitat de fer servir un identificador artificial (que no es correspongui a cap atribut del model conceptual) i fer que Hibernate generi els identificadors per als diferents objectes de manera automàtica.

Els “Value Types” son tipus de dades que, tot i que es corresponen a una classe java, no tenen entitat pròpia al domini (típicament no tenen identificador ni taula pròpia al model lògic de la base de dades). El cas paradigmàtic és l’adreça. En el nostre exemple, podem veure que les taules Employees,Suppliers i Customers comparteixen un conjunt d’atributs relatius a l’adreça: (address, city, region, postalCode i country). Si volguessim agrupar aquests atributs en una mateixa classe, l’hauriem de mapejar com a objecte i afegir l’anotació @Embedded a la propietat de l’entitat (si no ho fem, Hibernate mirarà igualment si la classe té l’anotació @Embeddable). Per exemple, a Employee tindriem:

    @Embedded
    public Address getAddress() {
        return this.address;
    }

    public void setAddress(Address value) {
        this.address = value;
    }
@Embeddable
public class Address implements java.io.Serializable {
    private String address;
    //...

    @Column(name="Address", length=60)
    public String getAddress() {
        return this.address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
    //...
}

Associacions

Només hem de tenir en compte associacions binàries ja que les associacions no binàries ja les haurem convertit en associacions binàries a l’hora de dissenyar el model del domini. Si que haurem de distingir, però, segons les possibles multiplicitats màximes (a un o a molts).

Multiplicitat màxima un

Al nostre exemple, tenim una associació entre Employee i Order on un Employee té moltes Order però una Order només té un Employee. Hauriem de mapejar, per una banda, la navegabilitat d’Order cap a Employee i, per altra, en el sentit invers.
ManyToOne
L’associació d’Order cap a Emploeyee és un cas d’associació ManyToOne, que és aquella en que, a la classe actual només hi ha un valor associat mentre que a l’altra en tenim més d’un. JPA defineix l’anotació ManyToOne per indicar una associació d’aquest tipus. Opcionalment, podem indicar la classe a la qual apunta l’associació o podem deixar que JPA la dedueixi a partir del tipus de la propietat anotada. L’anotació JoinColumn ens permet indicar a través de quina columna hem de fer la join (és a dir, quina columna conté la clau forana cap a Employee):

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="EmployeeID")
    public Employee getEmployee() {
        return this.employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

Hem mapejat l’associació com a “lazy loading”. Això significa que, quan carreguem una instància d’Order, no carregarem l’Employee associat fins que hi accedim.

OneToMany
Per mapejar l’associació en sentit invers d’Employee a Order) hem de considerar l’associació com a OneToMany i indicar que aquesta associació està mapejada a una altra entitat

    @OneToMany(mappedBy="employee")
    public Set getOrders() {
        return this.orders;
    }
    public void setOrders(Set orders) {
        this.orders = orders;
    }

En aquest exemple, el subsistema de JPA deduirà, a partir del tipus de la propietat (Set) que l’entitat on està mapejada l’associació en sentit invers és Order i, per tant, no cal indicar-ho.

Multiplicitat màxima molts

Com a exemple d’associació M:N (ManyToMany) agafarem l’associació entre Employee i Territory. Hem d’indicar el nom de la taula intermitja on es guardaran les instàncies de l’associació:
No s’ha indicat a l’exemple l’anotació @JoinTable

    @JoinTable(
        name="EmployeeTerritories",
        joinColumns= @JoinColumn(name="EmployeeID"),
        inverseJoinColumns = @JoinColumn(name="TerritoryID")
    )

i anotar les dues propietats

    // A Territory
    @ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="territories")
    public Set getEmployees() {
        return this.employees;
    }

    public void setEmployees(Set employees) {
        this.employees = employees;
    }

    //A Employee
    @ManyToMany(mappedBy="employees")
    public Set getTerritories() {
        return this.territories;
    }

    public void setTerritories(Set territories) {
        this.territories = territories;
    }

Conclusions

Hem vist un principi de com es pot anotar un model del domini per indicar les metadades de persistència, però no hem entrat en altres temes importants que s’han de decidir i dependran del sistema que estiguem desenvolupant com ara les estratègies de generació (podem generar el model del domini a partir del model físic de la base de dades o viceversa), les diferents possibilitats de mapeig d’associacions i col·lecions, el tractament de l’herència, les diferents estratègies de generació d’identificadors, etc. Un bon llibre on trobar més informació al respecte és Java Persistence with Hibernate, escrit per dos dels autors de Hibernate i que conté més de 800 pàgines d’informació sobre l’ús de Hibernate i JPA.


Identificació de casos d’ús

Posted: Abril 16th, 2009 | Author: Jose Raya | Filed under: agilogy | Comentarios desactivados

La major part del material d’aquest article està basada en les idees del llibre Writing Effective Use Cases d’ Alistair Cockburn. La meva intenció amb aquest document és donar una visió general de les idees que allà es detallen amb exemples i explicacions més exhaustives.

¿Què és un cas d’ús?

Un cas d’ús captura un contracte entre algú que fa servir un sistema i el propi sistema. Descriu el comportament del sistema indicant com ha de reaccionar a les accions de l’usuari. Per tant, els casos d’ús del sistema formen part del recull de requisits del mateix però no són tots els requisits (no inclouen la interfície gràfica d’usuari, regles de negoci, formats de dades, requisits tecnològics, requisits legals, etc.).

Un cas d’ús contempla diversos escenaris possibles. Alguns acaben bé i d’altres no, però tots els escenaris formen part del cas d’ús. Hi ha un escenari principal: aquell en el qual l’entitat qui ha engegat el cas d’ús aconsegueix satisfer l’objectiu pel qual l’havia engegat (hauria de ser el més “habitual”). Ex: En el cas d’ús “Comprar accions via web”, l’escenari principal és aquell en què el comprador aconsegueix comprar les accions.

¿A qui li afecta el cas d’ús?

Un cas d’ús descriu un contracte entre un “stakeholder” i el sistema. Un stakeholder és qualsevol entitat amb algun interés sobre el sistema, independentment de si interactua amb ell o no. Ex: El director general d’una empresa pot estar interessat en el sistema de facturació encara que no hi interactui directament.
Un actor, en canvi, és una entitat (una persona o un sistema informàtic) que interactua amb el nostre sistema. L’actor principal d’un cas d’ús és l’entitat que inicia la interacció amb el sistema.

¿Com es poden identificar ?

L’actor principal, quan decideix interactuar amb el sistema, ho fa amb un objectiu: aprofitarem aquest fet per descriure els casos d’ús en termes d’actors i objectius i per descobrir els casos d’ús:

  • Primer identifiquem els actors principals
  • Després identifiquem els casos d’ús per cada actor

Com que no només els actors tenen interessos respecte al sistema, podem generalitzar aquest enfocament a tots els stakeholders. Un cop identificat el cas d’ús, hem de tenir en compte que quan un actor engega un cas d’ús amb un objectiu el sistema té la responsabilitat de satisfer aquest objectiu. Per a dur a terme aquesta responsabilitat haurà d’identificar subobjectius, recolzar-se en altres actors de suport, establir mecanismes per a recuperar-se en cas de no poder satisfer aquest objectiu, etc.
Aquesta descomposició ens porta a plantejar-nos la següent qüestió:

Fins a quin punt descomposem els casos d’ús?

Normalment en tindrem prou amb tres nivells de detall (tot i que, al seu llibre, en Cockburn identifica alguns més).

  • Objectius generals (summary) (”sky-level”)
  • Objectius d’usuari (user) (”sea-level”)
  • Subobjectius (subfunctions) (”fish-level”)

Objectius generals

Son el nivell més alt i ténen com a propòsit i mostren el context en el què operen els objectius d’usuari. Mostren la seqüència relativa i el cicle de vida dels objectius relacionats. A més, serveixen com a “resum” del contingut dels casos d’ús que té per sota.

Objectius d’usuari

Son els més importants ja que són aquells per causa dels quals els usuaris (de manera més general, els actors principals) interactuen amb el nostre sistema. Idealment, un cas d’ús d’aquest nivell ha de proporcionar un cert valor per a l’actor que l’inicia; com a heurístic per identificar aquest valor podem fer qualsevol d’aquestes dues proves:

  • Test del café: Quan hagi acabat el cas d’ús, me’n puc anar a fer un café?
  • Test del sou: Si faig això 10 vegades en un dia, està justificat dir que m’he guanyat el sou?

Subobjectius

Son aquelles tasques que es requereixen per a dur a terme els objectius dels usuaris com ara cercar un producte, guardar un fitxer, etc. Normalment, només s’han de descriure en aquells casos en què la interacció sigui rellevant per algún motiu i que no hagi quedat clara en el cas d’ús d’usuari què l’inclou.

Errors habituals

Finalment, un petit recull d’errors habituals en el procés d’identificació i descripció dels casos d’ús:

  • Massa dependència respecte a la interfície d’usuari
  • Els casos d’ús formen part del recull de requisits, no del manual d’usuari. Per tant, el cas d’ús hauria de parlar d’intencions i objectius, no de pantalles.

  • No parlar sobre el sistema
  • Si només indiquem què fa l’actor però no indiquem què fa el sistema, no estem describint el comportament del sistema. Per tant, sempre hem d’intentar posar qui fa què

  • Objectius de molt baix nivell
  • La descomposició de casos d’ús generals en casos d’ús detallats és semblant a la descomposició funcional, però els casos d’ús són requisits, no disseny i, per tant, l’estructura dels casos d’ús no s’hauria de reflectir al codi. La descomposició funcional no funciona bé per als sistemes OO ja que dificulta la reusabilitat dels objectes


Lean Software Development: Evitar el despilfarro

Posted: Abril 16th, 2009 | Author: Jose Raya | Filed under: agilogy | Comentarios desactivados

A priori, “waste” (en adelante, despilfarro) es “todo aquello que no añade valor para el cliente”. Esto significa que, a priori, deberíamos producir solamente aquellas cosas que aportan un valor visible para el cliente, lo que nos lleva a reflexionar sobre el valor que aporta, por ejemplo, una especificación formal de requisitos o un diseño detallado con contratos OCL.

El cliente, normalmente, no verá dicha documentación, por lo que difícilmente podrá aportarle un gran valor. Sin embargo, como desarrolladores, sabemos que la documentación tiene el potencial de ayudarnos a desarrollar mejor, con mayor calidad, por lo que, indirectamente, estaría aportando valor al cliente. Esta es, en mi opinión, la principal trampa en cuanto a este principio, ya que una vez abrimos la vía del valor “indirecto”, cualquier actividad podrá encajar en dicha categoría.

¿Cómo podemos, entonces, identificar el despilfarro? Shigeo Singo, uno de los desarrolladores del “Toyota Production System” identificó siete tipos de “desperdicio” que los Poppendieck trasladan al mundo del desarrollo de la siguiente manera:

  1. Inventario -> Trabajo no finalizado
  2. Procesamiento extra -> Procesos extra
  3. Sobreproducción -> Funcionalidades de más
  4. Transporte -> Cambio de tareas
  5. Espera -> Espera
  6. Movimiento -> Movimiento
  7. Defectos -> Defectos

En mi opinión, la traslación al mundo del desarrollo es perfectamente correcta. Los desarrolladores no tenemos inventario que almacenar pero sí tenemos tareas que realizar y funcionalides que implementar. Acumular trabajo no finalizado es un riesgo que no deberíamos asumir a la ligera. En este sentido, considero muy interesante el concepto de “Definition of Done” [1] que, básicamente, viene a obligarnos a decidir en qué momento está finalizada una tarea, de modo que no la cerramos en falso ni seguimos dedicándole esfuerzo una vez la hemos finalizado.

Un punto en el que ha habido cierta controversia [2] ha sido respecto a si el “product backlog” es o no despilfarro. En general coincido con la opinión de que un backlog excesivamente detallado sería equivalente a un exceso de inventario, por lo que es necesario cuidar el backlog y mantenerlo “en forma” o lo que Mike Cohn denomina [3] el “Product backlog iceberg”. La idea es sencilla: se trata de ir refinando las historias de usuario (requisitos) a medida que se van convirtiendo en más prioritarias y se va acercando el momento de su implementación. De este modo tendremos, al principio del sprint, las historias más prioritarias (y que podrían entrar en este sprint) bien detalladas, el resto de historias que irán en esta release pero son menos prioritarias menos detalladas y, finalmente, aquellas que no irán en esta release las tenemos poco detalladas (normalmente en forma de “epic”). De este modo no realizamos trabajo innecesario y el backlog no se convierte en “desperdicio”. Otro enfoque es el que propone Mary Poppendieck en [4]: calcular el tiempo medio de permanencia de una historia en el backlog y eliminar todas aquellas que lleven más tiempo en el backlog que dicha media bajo el supuesto de que se están acumulando al final del backlog y que, probablemente, nunca llegarán a subir (serían algo así como el poso del backlog).

En cuanto a los procesos extra, por más formal que pretenda ser una metodología, no conseguirá evitar los malentendidos en cuanto a requisitos o la introducción de defectos. De hecho, la práctica demuestra que las metodologías ligeras y ágiles son más efectivas para solucionar estos problemas que las metodologías pesadas. Evidentemente, siempre hay que tener en cuenta el contexto, ya que por ejemplo, al desarrollar el software de control de un avión, hay poco margen a la interpretación y al cambio de requisitos (por no decir lo complicado que debe ser traer a la fábrica a todos los aviones para actualizarles el software). En este sentido, los Poppendieck proponen que nos hagamos una pregunta muy sencilla: ¿hay alguien esperando a que esto sea producido? Es obvio, por ejemplo, que si no hay nadie esperando a que un documento esté finalizado podremos considerarlo como superfluo ya que “nadie va a echarlo de menos”. De este modo, la necesidad o no de cualquier artefacto dependerá del contexto. Por ejemplo, un documento detallado de diseño puede ser requerido por la implementación de la ISO en una cierta organización mientras que en otra se trabaje sin este requisito. En este caso, el documento de diseño sería superfluo para el segundo equipo pero no para el primero.

¿Quién no ha dicho nunca aquello de ya que estamos, no nos cuesta nada añadir una opción para hacer …(a rellenar por cada cual) ? Sin embargo, como usuarios, es posible que la funcionalidad en cuestión no nos aporte gran cosa, es más, incluso puede que nos distraiga de otras funcionalidades más importantes. No deberíamos perder de vista casos como el del iPod, que consiguió monopolizar todo su mercado gracias a una interfaz de usuario simple a pesar de que le faltasen funcionalidades tan primitivas como la de borrar una canción. Este es el peligro de sobreproducción para los equipos de desarrollo: Desarrollar funcionalidades que, en el mejor de los casos no aportan valor y, en el peor, complican la experiencia de usuario.

Durante el desarrollo de software prácticamente no hay costes de transporte, pero es cierto que hay un cambio constante de niveles de abstracción; tan pronto estamos en la mente de un usuario sin conocimientos de informática que intenta darse de alta en nuestro sistema como estamos solucionando un problema con una herramienta superavanzada de mapeo objeto-relacional o corrigiendo un problema con la implementación del CSS de cualquier navegador. Estos cambios de abstracción son costosos y nos hacen perder la concentración, por lo que es importante evitar realizar varias tareas al mismo tiempo. También es costoso el cambiar entre proyectos o actividades (y como desarrollador-emprendedor-profesor sé perfectamente de qué hablo). Es por esto que las metodologías ágiles proponen siempre equipos con dedicación completa al proyecto.

Las esperas no necesitan traslación. Cada vez que alguien está parado esperando que algo pase se está desperdiciando su tiempo, incluso en el caso de que dicha persona pase a dedicarse a otra tarea (con lo que incurrimos en otro tipo de “desperdicio”) estaremos incrementando el volumen de trabajo a medias (nuestro inventario) y retrasando la obtención de valor por parte del usuario. En el caso de Scrum, una de las tareas fundamentales del “Scrum Master” es, precisamente, eliminar los impedimentos que hacen que los desarrolladores estén esperando.

El movimiento, en nuestro caso, no se limita a movimiento físico de piezas sino que los Popeendieck proponen (creo que con acierto) aplicarlo al movimiento de artefactos entre equipos y personas. Cada vez que un artefacto (documento de requisitos, análisis, etc.) se mueve hay una parte de información que se pierde ya que, por más exhaustivos que sean los documentos, nunca reflejarán el 100% de la información que recibió la persona/equipo que escribió el documento. Para reducir este tipo de despilfarro lo más fácil es reducir el número de artefactos. En este sentido, lo ideal sería que el propio desarrollador que implementará la funcionalidad fuese quien hablase con el cliente/stakeholder/usuario para obtener los requisitos de primera mano (esta es la parte “Conversation” del Card-Conversation-Confirmation de las historias de usuario). Eso sí, esta filosofía va radicalmente en contra del mito del “informático-sin-habilidades-sociales-que-se-encierra-en-su-cueva-y-no-habla-con-las-personas-porque-nadie-le-entiende” (y ya va siendo hora de que vayamos derribando ese mito).

Finalmente, para reducir el despilfarro asociado a la presencia de defectos nada mejor que probar intensivamente todo el código (pruebas unitarias, de integración, de aceptación, etc.), así como realizar integración contínua.

No voy a hablar aquí de la técnica del “Value Stream Mapping” puesto que considero que ya hemos tenido una primera aproximación al mundo del “despilfarro” y ya me he extendido más de lo que había pensado incialmente.

[1] http://www.scrumalliance.org/articles/105-what-is-definition-of-done-dod

[2] http://www.infoq.com/news/2007/10/product-backlogs-wasteful

[3] http://www.mountaingoatsoftware.com/system/presentation/file/78/Cohn_PrioritizingYourBacklog.pdf

[4] http://tech.groups.yahoo.com/group/leanagilescrum/message/332

[5] http://martinfowler.com/bliki/TechnicalDebt.html