miércoles, 24 de febrero de 2010

Lean

Lean manufacturing o Lean production, conocido normalmente como Lean, es una es una filosofía de gestión cuyo origen principal es el TPS (Toyota Production System), y que considera como desperdicio cualquier gasto de recursos que no esté orientado a la creación de valor para el cliente. Lo que intenta es crear un mayor valor con el menor gasto.

Lean intenta optimizar el flujo del proceso de producción, tratando de incrementar la eficiencia, reducir el gasto, y usar métodos empíricos para decidir qué es lo verdaderamente importante.

La metodología de desarrollo de software Lean es una translación de los principios y prácticas de la manufacturación Lean hacia el dominio del desarrollo del software. El desarrollo de software Lean tiene origen en el un libro del mismo nombre, escrito por Mary y Tom Poppendieck.

El desarrollo Lean se resume en los siguientes siete principios:
  • Eliminar los residuos.
  • Fomentar el aprendizaje.
  • Retrasar las decisiones.
  • Reaccionar rápidamente.
  • Potenciar el equipo.
  • Fomentar la integridad.
  • Ver todo el conjunto.

A continuación, pasamos a explicar cada uno de estos principios.

Eliminar los residuos

En Lean, todo lo que no añade valor al cliente se considera un residuo. Hay que ser capaz de reconocer las actividades que son residuos. Si el resultado esperado se puede alcanzar sin realizar alguna actividad, esta actividad es un residuo:
  • La codificación parcial eventualmente abandonada durante el proceso de desarrollo es un residuo.
  • Los procesos extra y funcionalidades que no utilizan con frecuencia por los clientes son residuos.
  • Las esperas ocasionadas por otras actividades, equipos o procesos son residuo.
  • Defectos y menor calidad son los residuos.
  • Gastos generales de gestión que no producen valor real son residuos.

A continuación se deben señalar las fuentes de los residuos y eliminarlos. Y todo ello debe hacerse de forma iterativa.

Fomentar el aprendizaje

El desarrollo de software es un proceso de aprendizaje continuo. La forma más eficaz para mejorar un entorno de desarrollo de software es el aprendizaje:
  • La acumulación de defectos debe evitarse ejecutando las pruebas tan pronto como el código está escrito.
  • En lugar de añadir más documentación o planificación detallada, las distintas ideas podrían ser juzgados escribiendo código y construyendo.
  • El proceso de recopilación de requisitos de usuarios podría simplificarse mediante la presentación de las pantallas de los usuarios finales y para que estos puedan hacer sus aportes.

El proceso de aprendizaje es acelerado por el uso de ciclos de iteración cortos que incrementan el feedback de los clientes, ayuda a determinar la fase actual de desarrollo y ajusta los esfuerzos para introducir mejoras en el futuro.

Durante estos ciclos, tanto los clientes como el equipo de desarrollo aprenden sobre el dominio del problema y buscar posibles soluciones para un mejor desarrollo. De esta forma los clientes comprenden mejor sus necesidades y los desarrolladores aprenden a satisfacerlas mejor.

Retrasar las decisiones

El desarrollo de software está siempre asociado con cierto grado de incertidumbre. Los mejores resultados se alcanzan cuando se puede decidir entre varias opciones basándose en hechos y no en suposiciones y pronósticos inciertos.

Cuanto más complejo es un proyecto, más capacidad para el cambio debe incluirse en este, así que debe permitirse el retraso en las decisiones importantes. Este enfoque de desarrollo puede llevar a opciones antes a los clientes. Por lo tanto, es conveniente retrasar algunas decisiones cruciales hasta que los clientes se hayan reconocido mejor sus necesidades. También permite la adaptación tardía a los cambios y previene de las costosas decisiones delimitadas por la tecnología.

Esto no significa que no haya un planificación del proceso. Por el contrario, las actividades de planificación se centran en las diferentes opciones y se las adapta a la situación actual. Esto permite clarificar las situaciones confusas y establecer las pautas para una acción rápida.

Reaccionar rápidamente

En el mercado actual, cuanto antes se entrega el producto final sin defectos considerables, más pronto se pueden recibir comentarios, que pueden ser incorporados en la siguiente iteración. Cuanto más cortas sean las iteraciones, mejor es el aprendizaje y la comunicación dentro del equipo.

La velocidad asegura el cumplimiento de las necesidades actuales del cliente y les da la oportunidad de demorarse pensando lo que realmente necesitan, hasta que adquieran un mejor conocimiento.

La ideología de producción Just In Time se aplica a programas de desarrollo. El equipo se organiza y se divide las tareas para lograr el resultado necesario para una iteración específica. El cliente dispone los requisitos necesarios en pequeñas historias y los desarrolladores estimarán el tiempo necesario para el desarrollo de cada una de ellas. Cada mañana, cada miembro del equipo evalúa lo que se ha hecho ayer, y lo que hay que hacer hoy y mañana, y pregunta por cualquier nueva entrada necesaria de parte de sus colegas o del cliente.

Otra idea clave se establece a base de diseño. Si un nuevo sistema es necesario, tres equipos pueden diseñar soluciones al mismo problema. Cada equipo aprende sobre el problema y diseña una posible solución. Cuando una solución se considera irrazonable, se desecha. Al final de un periodo, los diseños sobrevivientes se comparan y se elige uno, quizá con algunas modificaciones basadas en el aprendizaje de los demás. Mediante esta práctica se minimiza el riesgo provocado por un solo gran diseño realizado por adelantado.

Potenciar el equipo

Hasta el momento los administradores dicen a los trabajadores cómo hacer su trabajo. Ahora, los roles cambian, los trabajadores son los que dicen qué acciones podrían tomarse y sugieren mejoras. Los directores de proyecto más experimentados dicen que la clave de éxito de los proyectos es: "Buscar la buena gente y dejarles hacer su propio trabajo".

Otra creencia errónea ha sido considerar a las personas como recursos. En el desarrollo de software, las personas necesitan motivación y un objetivo hacia el cual trabajar, con la garantía de que el equipo puede elegir sus propios compromisos. Los desarrolladores deberían tener acceso a los clientes, el jefe de equipo debe proporcionar apoyo y ayuda en situaciones difíciles, y asegurarse de mantener el espíritu de equipo.

Fomentar la integridad

La integridad consiste en que los componentes separados del sistema función bien tanto juntos como en un todo.

Una de las maneras más saludables hacia una arquitectura que mantinen la integridad es la refactorización, que consiste en mantener la sencillez, la claridad, la cantidad mínima de funcionalidades en el código. Las repeticiones en el código son signo un mal diseños de código y deben evitarse. El completo y automatizado proceso de construcción debe ir acompañada de una suite completa y automatizada de pruebas, tanto para desarrolladores y clientes, que tengan la misma versión, sincronización y semántica que el sistema actual.

Al final, la integridad debe ser verificada con una prueba global, garantizando que el sistema hace lo que el cliente espera haga.

Ver todo el conjunto

Los sistemas de software hoy en día no son simplemente la suma de sus partes, sino también el producto de sus interacciones. Cuanto mayor sea el sistema, más serán las organizaciones que participan en su desarrollo y más partes son las desarrolladas por diferentes equipos; mayor es la importancia de tener bien definidas las relaciones entre los diferentes proveedores, con el fin de producir una buena interacción entre los componentes del sistema.


Para terminar, simplemente quiero recalcar que Lean define los principios a aplicar en un desarrollo de software, pero no la forma concreta de aplicarlos.

Referencias:
Desarrollo software Lean
Lean Manufacturing
Lean software development

martes, 23 de febrero de 2010

Patrones de diseño: Prototype

El patrón Prototype es un patrón de diseño creacional en el que los objetos se crean a partir de una instancia prototípica, que es clonada para dar lugar a nuevos objetos.

Este patrón se usa en los siguientes casos:
  • Para evitar las subclases de un objeto creador como hace el patrón Abstract Factory.
  • Para evitar el costo inherente a la creación de un objeto nuevo mediante el operador new cuando esto demasiado costoso para la aplicación.

Para implementar este patrón, se declara una clase base abstracta que tiene un método clone(). Cualquier clase que necesite un constructor deriva de la clase abstracta e implementa el método clone().

El cliente, en vez de escribir codigo que hace uso del operador new sobre una clase específica, llama al método clone() de la clase prototipo, o llama a un método factoría con un parámetro que especifica la clase deseada, o invoca el método clone() de la clase de alguna otra forma.

El siguiente diagrama UML representa este patrón:

Un ejemplo en Java de este patrón es el siguiente, sacado de la Wikipedia:
/** Prototype Class */
abstract class PrototypeFactory implements Cloneable {
public PrototypeFactory clone() throws CloneNotSupportedException {
// call Object.clone()
PrototypeFactory copy = (PrototypeFactory) super.clone();
//In an actual implementation of this pattern you might
//now change references to
//the expensive to produce parts from the copies
//that are held inside the prototype.
return copy;
}

abstract void prototypeFactory(int x);
abstract void printValue();
}

/** Concrete Prototypes to clone */
class PrototypeImpl extends PrototypeFactory {
int x;

public PrototypeImpl(int x) {
this.x = x;
}

@Override
void prototypeFactory(int x) {
this.x = x;
}

public void printValue() {
System.out.println("Value :" + x);
}
}

/** Client Class */
public class PrototypeExample {
private PrototypeFactory example;
// Could have been a private Cloneable example.

public PrototypeExample(PrototypeFactory example) {
this.example = example;
}

public PrototypeFactory makeCopy() throws CloneNotSupportedException {
return this.example.clone();
}

public static void main(String args[]) {
try {
PrototypeFactory tempExample = null;
int num = 1000;
PrototypeFactory prot = new PrototypeImpl(1000);
PrototypeExample cm = new PrototypeExample(prot);
for (int i = 0; i < 10; i++) {
tempExample = cm.makeCopy();
tempExample.prototypeFactory(i * num);
tempExample.printValue();
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}

También se puede combinar el uso del patrón Prototype con el de Factory Method, como en el siguiente ejemplo, también extraído de la Wikipedia:
// Los productos deben implementar esta interface
public interface Producto extends Cloneable {
Object clone();
// Aqui van todas las operaciones comunes a los productos que genera la factoria
}

// Un ejemplo basico de producto
public class UnProducto implements Producto {
private int atributo;

UnProducto(int atributo) {
this.atributo = atributo;
}

public Object clone() {
return new UnProducto(this.atributo);
}

public String toString() {
return ((Integer)atributo).toString();
}
}

// La clase encargada de generar objetos a partir de los prototipos
public class FactoriaPrototipo {
private HashMap mapaObjetos;
private String nombrePorDefecto;

public FactoriaPrototipo() {
mapaObjetos = new HashMap();
// Se incluyen al mapa todos los productos prototipo
mapaObjetos.put("producto 1", new UnProducto(1));
}

public Object create() {
return create(nombrePorDefecto);
}

public Object create(String nombre) {
nombrePorDefecto = nombre;
UnProducto objeto = (UnProducto)mapaObjetos.get(nombre);
return objeto != null ? objeto.clone() : null;
}
}

public class PruebaFactoria {
static public void main(String[] args) {
FactoriaPrototipo factoria = new FactoriaPrototipo();
Producto producto = (Producto) factoria.create("producto 1");
System.out.println ("Este es el objeto creado: " + producto);
}
}

Referencias:
Prototype (patrón de diseño)
Prototype pattern
Prototype Pattern – Patron Prototipo — Patrones de diseño
Un ejemplo del Patrón Prototype ( la versión Java )
Pattern Summaries: Prototype
Prototype Design Pattern, UML diagram, Java Example
Otros patrones de diseño

jueves, 11 de febrero de 2010

Sonar: Métricas de calidad del código

Según su propia web, Sonar es una plataforma que permite gestionar la calidad del código controlando los 7 ejes principales de dicha calidad del código:
  • Arquitectura y diseño
  • Duplicaciones
  • Pruebas unitarias
  • Complejidad
  • Errores potenciales
  • Reglas de codificación
  • Comentarios

Sonar realiza varios análisis de nuestro código a través de otras herramientas (Checkstyle, PMD, Cobertura…) y presenta de manera unificada a través de su interfaz la información generada por ellas en forma de métricas.

A través de la interfaz de Sonar podemos ver de forma detallada los puntos débiles de nuestro proyecto como errores potenciales en el código, escasez de comentarios, clases demasiado complejas, escasez de cobertura de las pruebas unitarias, y más.

Lo mejor es ilustrar la potencia de esta herramienta con un ejemplo de su uso, para lo cual vamos instalarla en nuestro equipo en primer lugar desde la página web del proyecto Sonar.

Descargamos la versión actual, que en este momento es la 1.12. Una vez que hemos descargado Sonar, tenemos un archivo .zip que podemos descomprimir en cualquier lugar, yo lo haré en la carpeta D:\java.

Por sencillez, para las pruebas vamos a lanzar el servidor de Sonar en modo standalone, aunque lo ideal sería instalarlo en un servidor de aplicaciones. Desde la línea de comandos vamos a la carpeta D:\java\sonar-1.12\bin\windows-x86-32 (estoy haciendo la prueba en Windows) y ejecutamos StartSonar.bat:

Esto lanzará el servidor de Sonar, al que podremos acceder desde la URL http://localhost:9000/:

Como acabamos de instalar Sonar, la interfaz aparecerá prácticamente vacía hasta que empecemos a analizar nuestros proyectos. Para ello iremos a uno de nuestros proyectos, gestionados con Maven, y le pediremos a Sonar que lo analice mediante el target de Maven mvn sonar:sonar:

Si ahora refrescamos la interfaz de Sonar, veremos que aparece el nuevo proyecto analizado:

Además ya nos va mostrando información sobre el proyecto, como el porcentaje de cumplimiento de las reglas de análisis o el porcentaje de cobertura de las pruebas unitarias. Pero, si queremos más información, no tenemos más que pinchar sobre nuestro proyecto para ir a la siguiente pantalla:

Aquí se empieza a ver la potencia de Sonar. En una interfaz compacta nos muestra una cantidad importante de información sobre el código del proyecto como:
  • medida en líneas de código
  • complejidad de los componentes
  • cantidad de comentarios introducidos
  • duplicidad del código
  • cobertura del código
  • conformidad respecto a ciertas reglas de codificación
  • violaciones del código

Para ampliar la información, podemos, por ejemplo, acceder a las violaciones tipo major de las reglas de codificación:

Sonar nos muestra información sobre las reglas que se están incumpliendo, y los paquetes y clases en que esto ocurre. Y, si pinchamos sobre una de las clases Sonar muestra cuál es el código que está incumpliendo estas reglas y da indicaciones para corregirlo:

A mí Sonar me ha parecido una maravilla, y no he hecho más que empezar a ver sus posibilidades. Os invito a que utilicéis esta herramienta y exploréis su interfaz en busca de toda la información que ofrece sobre el código del proyecto.

Referencias:
Página web del proyecto Sonar
Métricas en Java: Sonar
Analizando la calidad del código Java con Sonar

martes, 9 de febrero de 2010

Patrones de diseño: Builder

El patrón Builder o Constructor es otro de los patrones creacionales. Este patrón permite separar la construcción de un objeto complejo de su representación, de modo que el mismo proceso de construcción pueda crear diferentes representaciones de este objeto.

La siguiente imagen muestra el diagrama de clases de este patrón:

  • Builder: interfaz abstracta para crear productos.
  • Concrete Builder: implementación del Builder, construye y reúne las partes necesarias para construir los productos.
  • Director: construye un objeto usando el patrón Builder.
  • Producto: El objeto complejo bajo construcción.

A continuación se muestra un ejemplo de este patrón, extraído de la Wikipedia. En este ejemplo tenemos un cocina (Director) que produce pizzas (Producto) de con diferentes características (Concrete Builder):

/** "Product" */
class Pizza {
private String dough = "";
private String sauce = "";
private String topping = "";

public void setDough(String dough) {
this.dough = dough;
}

public void setSauce(String sauce) {
this.sauce = sauce;
}

public void setTopping(String topping) {
this.topping = topping;
}
}

/** "Abstract Builder" */
abstract class PizzaBuilder {
protected Pizza pizza;

public Pizza getPizza() {
return pizza;
}

public void createNewPizzaProduct() {
pizza = new Pizza();
}

public abstract void buildDough();

public abstract void buildSauce();

public abstract void buildTopping();
}

/** "ConcreteBuilder" */
class HawaiianPizzaBuilder extends PizzaBuilder {
public void buildDough() {
pizza.setDough("cross");
}

public void buildSauce() {
pizza.setSauce("mild");
}

public void buildTopping() {
pizza.setTopping("ham+pineapple");
}
}

/** "ConcreteBuilder" */
class SpicyPizzaBuilder extends PizzaBuilder {
public void buildDough() {
pizza.setDough("pan baked");
}

public void buildSauce() {
pizza.setSauce("hot");
}

public void buildTopping() {
pizza.setTopping("pepperoni+salami");
}
}

/** "Director" */
class Cook {
private PizzaBuilder pizzaBuilder;

public void setPizzaBuilder(PizzaBuilder pb) {
pizzaBuilder = pb;
}

public Pizza getPizza() {
return pizzaBuilder.getPizza();
}

public void constructPizza() {
pizzaBuilder.createNewPizzaProduct();
pizzaBuilder.buildDough();
pizzaBuilder.buildSauce();
pizzaBuilder.buildTopping();
}
}

/** A given type of pizza being constructed. */
public class BuilderExample {
public static void main(String[] args) {
Cook cook = new Cook();

PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();
PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();

cook.setPizzaBuilder(hawaiianPizzaBuilder);
cook.constructPizza();

Pizza pizza = cook.getPizza();
}
}

Hay quién confunde el patrón Builder con Factory, pero la diferencia es que, mientras el patrón Factory difiere la elección de la clase concreta de un objeto, el patrón Builder simplemente oculta la lógica de creación de un objeto complejo.

Referencias:
Patrón Builder en Wikipedia
Builder
Builder Pattern, Interfaces Fluidas– Patrones de diseño
Intro to Design Patterns: Builder Pattern
Creational Patterns - Builder Pattern
Design Pattern - Builder Pattern
Otros patrones de diseño


martes, 2 de febrero de 2010

Patrones de diseño: Factorías

Una factoría es un objeto que maneja la creación de otros objetos. Las factorías se utilizan cuando la creación de un objeto implica algo más que una simple instanciación.
Los siguientes ejemplos son casos donde una factoría puede ayudar:
  • Es necesario acceder a algún recurso para la creación y configuración de un objeto.
  • No conocemos hasta el momento preciso de la instanciación qué tipo concreto de objeto se va a instanciar.

En estos casos, en lugar de que sea el propio objeto quien se encargue de todos los aspectos realativos a la creación, se crea otro objeto que lo haga. De esta manera, se libera al objeto que va a ser creado de aquellas responsabilidades que no le corresponden pero que son necesarias para su creación, manteniendo su independencia.

El siguiente es un ejemplo de la utilización de una factoría para la creación de objetos. Se pueden crear figuras geométricas y calcular su área. Las figuras estarían definidas por una interfaz. Las figuras posibles son círculos y cuadrados.

Se va a utilizar una factoría para crear las figuras, puesto que no conocemos de antemano a qué clase pertenece el objetoque tenemos que instanciar. El uso de una factoría permite separar la lógica de negocio, igual para todos los casos, de la lógica de instanciación de los objetos. De este forma el código queda más claro.
public interface Figura {
public double getArea();
}

public class Circulo implements Figura {
double radio;

public Circulo(double radio) {
this.radio = radio;
}

public double getArea() {
return (3.14 * radio * radio);
}
}

public class Cuadrado implements Figura {
double lado;

public Cuadrado(double lado) {
this.lado = lado;
}

public double getArea() {
return lado * lado;
}
}

public class Principal {
public static void main(String[] args) {
int tipo = Integer.parseInt(args[0]);
double lado = Double.parseDouble(args[0]);

Figura figura =
FiguraFactory.getFigura(tipo, lado);

System.out.println("El area de la figura es: " + figura.getArea());
}
}

public class FiguraFactory {
public final static int CUADRADO = 0;
public final static int CIRCULO = 1;

public static Figura getFigura(int tipo, double lado) {
switch (tipo) {
case CUADRADO:
return new Cuadrado(lado);
case CIRCULO:
return new Circulo(lado);
}
return null;
}
}


El ejemplo anterior se corresponde con el patrón de diseño Factory Method, que se refiere a la utiliación de un método cuyo propósito principal es la creación de objetos.

Existe otro patrón de diseño denominado Abstract Factory, que proporciona una interfaz para crear familias de objetos que dependen entre sí, sin especificar sus clases concretas.

El siguiente es un ejemplo de una factoría abstracta sacado de la Wikipedia, en el que se crea un botón que puede pertenecer a dos familias distintas de componentes gráficos y la aplicación no sabe hasta el momento de la ejecución a qué familia pertenecerá este botón:


interface GUIFactory {
public Button createButton();
}

class WinFactory implements GUIFactory {
public Button createButton() {
return new WinButton();
}
}

class OSXFactory implements GUIFactory {
public Button createButton() {
return new OSXButton();
}
}

interface Button {
public void paint();
}

class WinButton implements Button {
public void paint() {
System.out.println("I'm a WinButton");
}
}

class OSXButton implements Button {
public void paint() {
System.out.println("I'm an OSXButton");
}
}

class Application {
public Application(GUIFactory factory){
Button button = factory.createButton();
button.paint();
}
}

public class ApplicationRunner {
public static void main(String[] args) {
new Application(createOsSpecificFactory());
}

public static GUIFactory createOsSpecificFactory() {
int sys = readFromConfigFile("OS_TYPE");
if (sys == 0) {
return new WinFactory();
} else {
return new OSXFactory();
}
}
}

Referencias:
Objeto Factoría en Wikipedia
Patrón Factoría en Wikipedia
Patrón Factory Method en Wikipedia
Factory Pattern - Patrones
Patrón Abstract Factory en Wikipedia
Abstract Factory Pattern - Patrones
Otros patrones de diseño