jueves, abril 22, 2010

Integración Continua para mantener el proyecto en rumbo

Hoy en día tenemos muchas herramientas que dicen limpiar de forma mágica nuestro código. Mueven, modifican, emprolijan y mágicamente resuelven todos nuestros problemas. Lamentablemente, como la mayoría ya sabe, escribir buen código lleva trabajo. No existen herramientas mágicas que puedan salvarnos (y no importa lo que nos digan los vendedores), pero si hay una herramienta que funciona muy bien para ayudarnos a mantenernos en forma.

La Integración Continua es una idea bien simple. Configuramos un programa que mire el código fuente. Cuando alguien hace algún cambio, el sistema de Integración Continua lo compila de inmediato. Si la compilación pasa, se ejecutan las pruebas automatizadas. Por último, se publican los resultados.

Simple, ¿no? ¿Por qué es tan poderoso?

La Integración Continua es como una tarjeta de crédito al revés. Una tarjeta de crédito nos permite comprar algo grande hoy, y pagarlo de a poquito más adelante. Sin embargo, las tarjetas de crédito tienen un pequeño secretito oscuro... el interés compuesto. Terminamos pagando mucho, mucho más de lo que tomamos prestado. Siempre resulta más barato pagar en efectivo si podemos.

Cuando usamos un sistema de Integración Continua, ocurre lo opuesto. Podemos hacer pequeños pagos todos los días, o podemos esperar hasta el final y hacer un único gran pago. ¡Desafortunadamente este último gran pago tiene todo el interés compuesto agregado! Si esperamos al final, terminamos pagando más... mucho más!

Esto ocurre por el "tiempo a oscuras" entre que un desarrollador escribe el código y lo combina con el código que escribió el resto del equipo. Si combinamos el código todos los días, o incluso un par de veces a la semana, los cambios son menores y relativamente indoloros. Pero si esperamos...

Si esperamos, los cambios crecen. Mientras más esperamos, más código escribimos. Y más código escribe el resto del equipo. Al terminar el mes, cuando nos vemos forzados a combinar y unir todos esos cambios, las colisiones son gigantes. Los desarrolladores trabajan en los mismos archivos, a veces en las mismas líneas... otras veces hay funcionalidad en la que un desarrallador dependía y ahora hay otro desarrollador que la cambió (quiero decir, "mejoró"). Y los cambios mutuamente excluyentes generan caos.

Durante este tiempo entre escribir el código y hacer la combinación, compilación y testeo con el código de los demás, es cuando no podemos ver lo que está pasando. ¿Nuestros cambios entran en conflicto con los de alguien más? ¿Alguien cambió algo que necesitamos? No podemos verlo todavía... estamos a oscuras. Y vamos a seguir a oscuras hasta que unamos el código.

Una herramienta de Integración Continua ayuda los desarrolladores a aprender el ritmo de "escribir una cosa, subirla al repositorio". Esto funciona mucho mejor que "escribir una cosa... y otra... y otra... y otra...", y después "dedicar horas y días a combinar el código". ¡Y ni siquiera empezamos a ahblar de los beneficios de ejecutar las pruebas automatizadas después de subir cada cambio!

Tenemos que encontrar los problemas lo más rápido posible, cuando todavía los arreglos son menores. ¡Es el mejor momento para arreglar los problemas!

Algunos productos de Integración Continua para empezar

Fuente: DosIdeas

miércoles, abril 21, 2010

Crear amor, no dinero

Algunas personas de negocios siguen una estrategia que no se enseña en las escuelas de negocios: la mejor forma de maximizar las ganancias es dejar de pensar en maximizar las ganancias y, en cambio, enfocarse en tratar bien a las personas. Es decir, la mejor forma de hacer dinero es enfocarse en amar a las personas.

Joel Spolsky ya lo dijo: "Las mejores condiciones de trabajo -> Los mejores programadores -> El mejor software -> ¡Ganancia!".

Tony Hsieh lo dice de esta forma: "La Cultura es nuestra prioridad número uno... Creemos que si generamos la cultura correcta, entonces muchas otras cosas como construir una marca van a ocurrir de forma natural por si mismas".

Quisiera distinguir esta visión de dos perspectivas similares: la primera es el estilo del colectivismo hippie de los '60, en el cual el capitalismo es malvado porque es inherentemente manipulativo, que el trabajo y el capital deberían beneficiar a todos los miembros de la organización, y que, en realidad, el dinero es una molestia y lo que importa es el amor. En contraste, la perspectiva de Crear amor, no dinero no dice que el dinero sea una molestia o cómo debería organizarse el capital. Tampoco quiere decir que sea inconsistente con el punto de vista hippie.

La segunda perspectiva proviene del mantra tradicional de Scrum: "El objetivo del equipo es maximizar el valor de negocio entregando software que funciona". Bajo la mirada de Crear amor, no dinero se podría re-escribir: "El objetivo de un equipo es optimizar su entorno de trabajo y, como efecto secundario beneficioso, va a incremental radicalmente el valor de negocio que se entrega". Es un hallazgo empírico que optimizar el entorno de trabajo suele llevar a incrementos significativos en los resultados financieros. Resulta consistente con el sentido común pero no necesarimante deriva de la premisa "optimizar el entorno de trabajo".

Una buena pregunta: ¿Por qué no hacen esto quienes maximizar las ganancias? El gerente típico medio, cuando se le pide que aumente las ganancias, responde despidiendo trabajadores o ahorrando en material de la oficina - no creando un gran entorno de trabajo. No sé porqué. Sospecho que tiene que ver con las limitaciones cognitivas de las personas. Nos resulta muy dificil comprender el enésimo efecto de nuestras acciones. Es mucho más simple comprar sillas baratas para lograrlo - cualquier otra cosa es más complicada.

Si se adoptara, quienes maximizan los beneficios podrían ver a la perspectiva de Crear amor, no dinero como una herramienta cognitiva que ayuda a tomar mejores decisiones, al igual que un coach de ajedrez enseña a desarrollar las piezas (en vez de pedirle que haga mate al rey).

En resumen: enfocarse en crear grandes ambientes de trabajo, y obtendremos gratis las ganancias extraordinarias.

Fuente: DosIdeas

lunes, abril 05, 2010

Lista de comprobación para hacer TDD

El Desarrollo Guiado por Pruebas (o TDD) se suele describir como un ciclo de rojo-verde-refactor, que se repite continuamente, para ir agregando nuevas características o arreglar bugs. La siguiente lista de comprobación que comparte Giorgio Sironi contiene un grupo de preguntas que deberíamos hacernos a nosotros mismos mientras avanzamos por las fases de TDD, para no olvidarnos de la esencia de esta técnica.

Rojo

El desarrollo de cualquier característica nueva tiene que empezar con una prueba que falla.

  • ¿Subiste el código al repositorio remoto o local? Si el código se rompe, es más fácil revertir los cambios que re-escribir.
  • ¿Ya escribiste código productivo? Si lo hiciste, comentalo o, mejor todavía, eliminalo para no estar atado implícitamente a un API mientras escribís la prueba.
  • ¿Elegiste la unidad apropiada para expandir? La clase modificada debería ser una que siga teniendo cohesión luego del cambio, y a menudo se deberían agregar claes nuevas en vez de acomodar la funcionalidad en las existentes.
  • ¿Falla la prueba? Si no, re-escribila para exponer la falta de funcionalidad.
  • ¿Una parte de la prueba ya falla? Si es así, eliminá el restante de la prueba; el resto lo podés agregar en métodos diferentes.
  • ¿El nombre del método de prueba describe su propósito? Asegurate de no atarte a detalles de implementación.
  • ¿Los mensajes de fallas son descriptivos sobre el problema? Asegurate que describan en dónde está fallando la funcionalidad, destacando la ubicación si se rompiera en el futuro.
  • ¿Los números y strings mágicos están expresados dentro de constantes? ¿Hay código repetido? El refactor del código de pruebas es más fácil cuando se hace tempranamente y mientras aún falla, ya que en este paradigma es más importante hacer que siga fallando que hacer que pase.

Verde

Se debe escribir el código productivo necesario para que la prueba pase.

  • ¿El código productivo hace pasar a la prueba? (así de simple)
  • ¿Hay un subconjunto del código productivo que hace pasar a la prueba? Si es así, comentá, o mejor todavía, eliminá el código productivo innecesario. Cualquier otra línea de código que escribas no tendrá cobertura, y serán líneas sin pruebas que deberemos leer y mantener en el futuro.
  • Cualquier otra acción específica será llevada a cabo en la fase de Refactor.

Refactor

Mejorar la estructura del código para facilitar los cambios futuros y el mantenimiento.

  • ¿Existe código repetido en la clase actual?
  • ¿El nombre de la clase es el apropiado?
  • ¿Los métodos públicos y protegidos tienen un nombre descriptivo? ¿Son legibles? El refactor de renombrado es uno de los más poderosos.
  • ¿Hay código repetido en diferentes clases? ¿Existe un concepto de dominio que está faltando? Podemos extraer hacia clases abstractas o hacer un refactor de composición. Este alto nivel de refactor también debería aplicarse a las clases de pruebas unitarias.
Fuente: DosIdeas

jueves, marzo 18, 2010

NoSQL y varias alternativas a las bases de datos

Hace un tiempo cubrimos la inauguración de la comunidad NoSQL, un movimiento para pensar alternativas a las bases de datos relacionales que tan acostumbrados nos tienen. En este artículo, Debasish Ghosh reflexiona sobre el futuro del movimiento y las diferentes alternativas que tenemos hoy en día.

Hoy en día somos testigos de muchas noticias alrededor de NoSQL. Llámese NoSQL (~SQL) o NOSQL (Not Only SQL - No solo SQL), el movimiento tiene una misión. No todas las aplicaciones necesitan almacenar y procesar datos de la misma manera, y por lo tanto la arquitectura de almacenamiento debería pensarse de forma acorde. Hasta hoy estuvimos forzados a usar el mismo martillo para pegarle a todos los clavos. Sin importar cómo procesáramos los datos de nuestra aplicación, los solemos almacenar como filas y columnas en bases de datos relacionales.

Cuando estamos tratando con grandes aplicaciones de escritura escalables, las bases relacionales apestan. La normalización de datos, los joins, y las transacciones ACID son anti-patrones para la escritura escalable. Quizás piensen que el sharding solucione los problemas, dividiendo los datos en porciones más pequeñas. En realidad, el mayor problema del sharding es que las bases de datos relacionales nunca fueron diseñadas para eso. El sharding quita muchos de los beneficios de las bases relacionales. El sharding no puede ser "algo para pensar después", ya que se entromete en la lógica del negocio de la aplicación, y hacer joins de múltiples shards puede resultar un esfuerzo no trivial. Mientras podamos escalar de forma vertical nuestro modelo de datos aumentando la capacidad del hardware, seguramente sea la opción más sana para adoptar. Pero según Moore... incluso aunque podamos escalar verticalmente, traten de migrar una base MySQL realmente grande. Les va a llevar horas, quizás días. Este es uno de los motivos por los cuales algunas empresas están migrando a bases de datos sin esquemas, cuando las aplicaciones así lo permiten.

Y si para escalar horizontalmente sacrificamos la normalización, los joins y las transacciones ACID, ¿por qué usar motores de bases de datos relacionales? No se necesitan... Digg está migrando de MySQL hacia Cassandra. Todo depende de la aplicación y del tipo de escalabilidad de escrituras que necesitemos lograr para procesar los datos. Para escalar la lectura, podemos usar esclavos de sólo-lectura que replican todo lo que llega a la base de datos maestra en tiempo real, y configurar un proxy inteligente entre los clientes y la base de datos.

El mayor entusiasmo que creó el movimiento NoSQL es por los enfoques divergentes que prometen cada uno de sus productos. Y esto es muy diferente al movimiento de motores de bases de datos relacionales, que comenzó como un único martillo llamado SQL que es capaz de manipular filas y columnas de tipos de datos sobre la teoría matemática de un conjunto de operaciones. Y cada aplicación adoptó la misma arquitectura de almacenamiento sin portar de cómo procesara los datos dentro de la aplicación. Una cosa llevó a la otra, las personas creyeron poder resolver el problema con otra capa de indirección... y así apareció esa cosa extraña llamada Mapeador Objeto-Relacional (ORM).

Finalmente, con el boom del procesamiento de datos en la Web, nos dimos cuenta que no todos los datos se procesan igual. El almacenamiento que funcionó tan bien para las aplicaciones de escritorio tradicionales, fracasa estrepitosamente con las aplicaciones sociales donde se necesitan procesar datos enlazados, que tienen la forma de grafos. La comunidad NoSQL respondió con Neo4J, una base de datos de grafos que brinda almacenamiento sencillo y recorrido de estructuras de grafos.

Si quieren escalar a lo grande la escritura, la única forma es la descentralización y la consistencia eventual. Aparece el teorema de CAP, en donde necesitamos comprometer la consistencia, la disponibilidad o la tolerancia a la partición de la red (elijan uno). Riak y Cassandra ofrecen almacenamiento descentralizado de datos que pueden escalar indefinidamente en la teoría. Si tu aplicación necesita más estructura que una base de datos clave-valor, pueden optar por Cassandra, el sistema de almacenamiento orientado a columnas, distribuido y peer-to-peer. Pueden mirar este artículo de Digg donde se compara su casos de uso entre el almacenamiento relacional y el almacenamiento por columnas que ofrece Cassandra. Si quieren una base de datos orientada a documentos con todos los beneficios de REST y JSON, prueben Riak. Riak también ofrece Map/Reduce enlazado con la opción de almacenar elementos enlazados de datos, muy parecido a la forma en que funciona la web. Riak realmente es un sistema de almacenamiento con la forma de la web.

CouchDB ofrece otra interesante propuesta para el ecosistema de NoSQL. La mayoría de las aplicaciones son básicamente offline y necesitan facilidades de replicación transparentes. CouchDB usa una estructura de almacenamiento de Árbol-B, operaciones de sólo agregado con un control de concurrencia basado en el modelo MVCC, operaciones sin bloqueos, API REST y operaciones incrementales Map/Reduce. Chris Anderson, uno de los desarrolladores líderes de CouchDB, resume el valor de CouchDB en el mundo web de hoy:

Las aplicaciones CouchApps son el producto de un navegador HTML5 y una instancia CouchDB. La ventaja clave es la portabilidad, basada en la plataforma HTML5. Las características como los Web Workers y el XHR cross-domain hacen una diferencia enorme en la arquitectura de la web. La disponibilidad en todas las plataformas es clave para el futuro de la web.

Al igual que CouchDB, MongoDB también ofrece almacenamiento de documentos. No brinda soporte REST, pero se basa en un almacenamiento JSON. También tiene Map/Reduce, y ofrece un poderoso conjunto de APIs de consulta muy parecido a SQL. Este es un punto clave de MongoDB, que le resulta muy cómodo a personas que tienen conocimientos de SQL. MongoDB también ofrece replicación maestro-esclavo, y están trabajando en escalabilidad basada en autosharding y en tolerancia a fallos.

Hay varios más sistemas de almacenamientos que ofrecen soluciones a problemas de todos los días. Caché, consumidores de colas que requieren operaciones push/pop atómicas, procesamiento de flujos de actividad, log de datos, etc. Redis y Tokyo Cabinet funcionan bien para estos casos. Redis es como caché en memoria con una base de datos persistente de clave-valor. Es un único hilo, utiliza IO no-bloqueante y es súper rápido. Redis, además de ofrece almacenamiento de clave-valor, también ofrece la posibilidad de almacenar listas y colecciones con operaciones atómicas.

Otro aspecto interesante es la interoperabilidad entre los sistemas de almacenamiento. Riak, por ejemplo, ofrece la posibilidad de usar distintos backends para los datos - podríamos usar CouchDB como backend para Riak. Posiblemente también veamos un backend Cassandra para Neo4J. Sin dudas es interesante ver como estas comunidades tienen este sentido de cooperaciones para hacer que todo el ecosistema sea más útil y crezca más.

Original: DosIdeas

jueves, febrero 25, 2010

Reportar Errores o Escribir Puebas Unitarias

Los sistemas de gestión de errores (o "bug trackers") son cuellos de botella, y perpetúan el continuo idea y vuelta entre testers y desarrolladores, además de requerir de mucha documentación para mantenerlos.

Alberto Gutierrez comparte una interesante reflexión sobre cómo crear el mejor sistema de gestión de errores: ¡dejar de reportar errores y empezar a escribir pruebas automatizadas!

El ciclo de vida estándar de un bug es más o menos así: un tester de QA encuentra un error en la aplicación, crea un nuevo reporte de bug en el bug tracker y se lo envia al desarrollador, quien a su vez, ni bien soluciona el bug, lo envia de vuelta al tester, quien a su vez notifica al dueño del producto y luego cierra el bug.

En la teoría este proceso suena bien, pero tiene varias desventajas:

  • Problemas de comunicación. A veces la descripción del bug es pobre, o el desarrollador malinterpreta el problema.
  • Pruebas de regresión. El proceso requiere de idas y vueltas de código entre desarrollo y QA, lo que ocasiona problemas de versionado y duplica el esfuerzo de testing.
  • No es robusto. El proceso no garantiza que el error no vuelva a aparecer en el futuro.
  • Burocracia. Los sistemas de bug tracking tradicionales cambian el foco de la calidad a la burocracia.

La solución a estos problemas es bastante simple. Cuando alguien encuentra un bug, inmediatamente escribe una prueba automatizada que falla sobre el bug descubierto. Este mecanismo tiene varias ventajas:

  • Desaparecen los problemas de versionado, todos trabajan en el head del código.
  • Se garantiza que el bug no vuelva a aparecer sin ser detectado.
  • Se elimina la ambigüedad sobre cuál es el bug exactamente.
  • Se elimina burocracia.
  • Consolida las actividades de desarrollo en un único lugar, el código.

Obviamente también hay desafíos a superar para cambiar a este proceso en donde no se necesita de un bug tracker:

  • Se necesita un sistema de construcción automatizado. La construcción del proyecto tiene que estar corriendo todas las pruebas automatizadas, de manera que cuando se agregue una nueva prueba por un bug, la construcción falle y el equipo de desarrollo pueda decidir corregir el error en el momento, o ignorarlo por un tiempo (de esta manera sabremos que todas las pruebas ignoradas son bugs sin arreglar).
  • Se necesita cooperación. Los desarrolladores y los testers tienen que trabajar juntos para crear las nuevas pruebas ni bien aparezca un bug. Se necesita tener testers con habilidades de programación.
  • Se necesita disciplina. Los equipos tienen que entender que se debe crear una prueba por cada bug encontrado, sin excepción. Y cada vez que se rompe la construcción, la prioridad es solucionarlo.
  • Se necesita organización. Las prueban tienen que crearse con criterio y usando alguna nomenclatura en común.

En resumen, en mi opinión el futuro de la gestión de errores es eliminar los bugs trackers tradicionales y toda la burocracia. Para lograr esto hay varios desafíos; si tienen las habilidades, las herramientas y el equipo para superar estos desafíos, podrían pensar seriamente en deshacerse del viejo sistema de gestión de errores.

Fuente: DosIdeas

viernes, enero 22, 2010

10 motivos para amar el test ágil

Recientemente, Kay Johansen hizo la pregunta "¿Por qué te gusta probar ágil?". Las respuestas varian desde desde las más serias a las más relajadas.
  • Tener la oportunidad realmente de impactar en la calidad y no sólo documentarla! (Juan Overbaugh) - cuando los defectos son corregidos de inmediato en lugar de ponerlos en una pila de defectos.
  • No más pruebas manuales de los scripts! En cambio, los scripts serán ejecutados automáticamente, proporcionando más tiempo para que el tester realice las pruebas de exploración.
  • Los desarrolladores realmente gustan de esto! - Localizar los problemas antes de la final de la interacción cuando el código está fresco en la mente de los desarrolladores, les ayuda a encontrar el problema.
  • Ahora puede comprobar los recursos antes de que sean escritos! (Kay y Philip) - El tester puede evitar problemas al iniciar la prueba antes que los recursos se definan.
  • Los resultados de las pruebas automatizadas se pueden ver muchas veces al día, proporcionando una rápida retroalimentación después de cualquier cambio.
  • El ambiente está muy orientado al equipo (Juan Overbaugh) - Cada miembro del equipo se preocupa de terminar las pruebas y no sólo el código (Lisa Crispin).
  • El tester puede ocasionalmente ajustar el defecto (Lisa Crispin) - Cada miembro del equipo se siente más cómodo ya que la prueba está automatizada.
  • Ofrece la oportunidad de revisar constantemente las prácticas de pruebas (Adam Knight) - En lugar de simplemente repetir lo que se ha hecho anteriormente, las prácticas son constante revisadas. En el caso de Adam las pruebas que acostumbraban tomar 5 días para ejecutarse manualmente se han reducido ahora a 30 minutos.
  • He pasado mucho menos tiempo en depuración (Adrian Howard) - tengo el feedback prácticamente al mismo tiempo que se ha cometido un error, por lo tanto, suele ser trivial localizar y corregir.
  • Siempre existe tiempo para probar porque la prueba se realiza primero - Josué Barbosa dos Santos contó la historia de trabajar en una oficina del gobierno en Brasil, donde la práctica era probar al final del proyecto. El desarrollo siempre estaba atrasado en el calendario del proyecto y terminaba siendo liberado a los usuarios sin pruebas. Con la introducción de TDD y ATDD las pruebas se ejecutaban mientras que el software era desarrollado.

El número uno para Kay de los motivos de amar la prueba ágil: es que puedo escuchar gente diciendo "este es el mejor proyecto que he trabajado en mi vida!"

Fuente: DosIdeas

5 consejos para construir software sin defectos

Lamentablemente, en algunas organizaciones todavía se considera al testing como la última etapa del proceso de desarrollo. Los desarrolladores entonces cruzan los dedos para programar todo lo más perfecto posible, de manera que la etapa de testing sea una formalidad donde a lo sumo se encuentren errores menores. Por suerte ya hace un tiempo que nos estamos alejando de esta utopía ridícula y vamos avanzando hacia un concepto en donde el testing es una parte integrada al proceso de desarrollo.

El artículo How to write good tests nos deja 5 consejos para aprovechar al máximo este nuevo enfoque.

  1. El código de test es tan importante como el código productivo. Uno de los problemas más comunes al empezar con TDD es que el código de test no es limpio ni tan prolijo como el productivo, de manera que eventualmente cuesta mucho mantenerlo. Para evitar este escenario es importante que el código de test sea tan prolijo como el productivo.
  2. Probar lo más posible, lo antes posible, lo más seguido posible. Es importante no avanzar en el código productivo hasta tener una prueba que verifique que el código escrito funcione como esperamos. Este enfoque logrará que nuestro sistema tenga menos defectos, y además nos dará mayor seguridad a futuro para implementar cambios.
  3. Probar en distintos niveles. No hay que ahogarnos con pruebas de integración que son muy dificil de escribir y lentas para ejecutar (y que, de última, no llegan a cubrir todos los elementos de la aplicación). El mejor enfoque es usar pruebas en distintos niveles. Por ejemplo:
    • Pruebas unitarias, que comprueban los componentes de forma aislada al resto.
    • Pruebas de aceptación, que son creadas por el Dueño del Producto y representan la funcionalidad mínima que tiene que tener la aplicación para poder aceptarse desde la perspectiva del negocio.
    • Pruebas de integración, que no son identificadas por el Dueño del Producto pero las desarrolla QA o el equipo de desarrollo como complemento.
    • Pruebas de interfaz de usuario. Son lentas y además cambian mucho, por lo que hay que mantenerlas separadas del resto de las pruebas.
  4. Integración continua. Las pruebas tienen que ser una parte fundamental e integral del proceso de desarrollo, que ocurren en cada instante del proceso. Todos son responsables por las pruebas, desde el desarrollador hasta QA y el Dueño del Producto. Las herramientas de integración continua nos ayudan enormemente a llevar adelante este desafio.
  5. Usar herramientas y frameworks de testing. No hay que reinventar la rueda, ni trabajar como en la edad de piedra. Tenemos muchas herramientas y frameworks de software libre que nos permiten implementar una estrategia seria de testing.
    • Fitnesse, una herramienta para crear pruebas de aceptación, de forma que personas no-técnicas puedan escribir sus propios escenarios.
    • xUnit, un framework para desarrollar pruebas unitarias, que se integra con todos los IDE de desarrollo en distintos lenguajes de programación.
    • Bugzilla, una herramienta para reportar bugs y hacer su seguimiento.
    • Selenium, una herramienta para crear pruebas automatizadas de interfaces de usuario web.
    • Hudson, una herramienta de integración continua que se usa para asegurar que el código siempre esté funcionando correctamente y pase todas las pruebas.
Fuente: DosIdeas

martes, septiembre 01, 2009

Novedades que tendrá el compilador en el JDK 7

Joseph Darcy nos cuenta las novedades que tendrá el compilador en el JDK 7. En general son cambios menores debatidos en los foros, que incluyen varias comodidades en la sintaxis del lenguaje.

Las novedades del JDK 7 serán:

  • Switch con objetos de tipo String
  • Gestión automática de recursos
  • Mejoras en la inferencia de tipos para la creación de Generics
  • Invocación de métodos con varargs simplificada
  • Mejoras en los literales numéricos
  • Soporte en el lenguaje para Collections
  • Soporte en el lenguaje para JSR 292

Veamos en detalle estas características.

Switch con objetos de tipo String

Será posible utilizar el operador switch con objetos de tipo String. De esta manera se evitan los potenciales "if-then-else". Entonces, esta nueva funcionalidad nos permitiría:


String s = ...
switch(s) {
case "quux":
procesarQuux(s);
// y seguir...

case "foo":
case "bar":
procesarFooBar(s);
break;

case "Gaz":
procesarGaz(s);
// y seguir...

default:
procesarPredeterminado(s);
break;
}

Gestión automática de recursos

Un "recurso" es un objeto que tiene que cerrarse manualmente, como ser java.io.InputStream, OutputStream, Reader, Writer, Formatter;
java.nio.Channel;java.net.socket; java.sql.Connection, Statement, ResultSet entre otros. Estos recursos se suelen abrir en un bloque try y cerrar en un finally.

La gestión automática de rcursos es una forma especial del operador try en donde se declaran uno o más recursos. El alcance de estos recursos está limitado al bloque. Cuando el bloque termina, sea de forma normal o abrupta, todos los recursos declarados se cierran automáticamente.

La principal ventaja es que se elimina la necesidad del cierre manual, y los posibles errores que eso provoca. Además, se "evita" la segunda excepción (la del close()), dejando siempre la excepción del bloque que suele ser más interesante.

Un ejemplo de uso sería:


static String readFirstLineFromFile2(String path) throws IOException {

try (BufferedReader br = new BufferedReader(new FileReader(path)) {

return br.readLine();

}
}

Como vemos, el bloque try() declara un recurso, el luego es utilizado dentro del bloque. Al finalizar, se cerrará automáticamente. También es posible declarar más de un recurso:


try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest)) {

byte[] buf = new byte[8192];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
}

Mejoras en la inferencia de tipos para la creación de Generics

Se incluirá la posiblidad de inferir los tipos para la creación de instancias usando Generics. En los casos que los tipos parametrizados sean obvios según el contexto, esta parametrización puede omitirse en el constructor y reemplazarse por un conjunto vacio: <>.

Por ejemplo, la siguiente línea:

     Map> anagrams = new HashMap>();

puede ser reemplazada por:

     Map anagrams = new HashMap<>();

Mejoras en los literales numéricos

Así como podemos declarar literales numéricos decimales, octales y hexadecimales, ahora también podremos declarar literales binarios. Esto resulta muy útil en ciertos ámbitos. Para esto se utiliza el prefijo 0b, el cual además es el mismo que usan los compiladores C/C++, Ruby y Python. Por ejemplo:


// Un literal 'byte' de 8-bits
byte aByte = (byte)0b00100001;

// Un literal 'short' de 16-bits
short aShort = (short)0b1010000101000101;

// Varios literales 'int' de 32-bit 'int'
int anInt1 = 0b10100001010001011010000101000101;
int anInt2 = 0b101;

Estas variables luego se usan normalmente; por ejemplo:


class Foo {
public static void main(String[] args) {
System.out.println("El valor decimal de 10100001 es " + 0b10100001);
}

Por otro lado, se agregó la posiblidad de usar un guión bajo (_) como separador de números, para facilitar la lectura de los mismos. De esta manera, el compilador ignorará al caracter "_" cuando sea utilizado en literales numéricos. Por ejemplo:


int numeroDeTelefono = 555_555_1212;
long tarjetaDeCredito = 1234_5678_9012_3456L;
long legajo = 999_99_9999L;
float cantidadDeDinero = 12_345_132.12;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xFFEC_DE5E;
long maxLong = 0x7fff_ffff_ffff_ffffL;
long bytes = 0b11010010_01101001_10010100_10010010;

Soporte en el lenguaje para Collections

Se agrega el soporte al lenguaje para tratar a las Collection como si fueran Arrays.

Por ejemplo, se podrá escribir lo siguiente para declarar un List inmutable:


final List piDigits = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9];

También será posible acceder a las listas y maps usando una sintaxis de arrays:


public class Main {
public static void main(String[] arguments) {
List lista = Arrays.asList(new String[] {"a", "b", "c"});
String primerElemento = lista[0]

Map m1 = new HashMap(4);
m1[Integer.valueOf(1)] = "One";
}

Soporte en el lenguaje para JSR 292

Este cambio de bajo nivel realizará modificaciones menores en el lenguaje Java para que se más simple trabajar con algunas características de la JVM. Esto va a permitir que el código Java pueda interoperar y/o implementar librerías en otros lenguajes. Es decir, se logrará una mayor integración entre Java y código en otros lenguajes. Para ver más detalles leer la propuesta del soporte para JSR 292.

Fuente: DosIdeas

martes, agosto 25, 2009

Plone: un sistema ágil y potente para de gestión de contenido

Plone: un sistema ágil y potente para de gestión de contenido

por Leonardo CaballeroContribuciones: dukebody

Fácil de empezar

Baterías incluidas

Soporta Linux, Windows, Mac OS X, FreeBSD, Solaris. Los programas de instalación le permiten ponerlo en marcha en sólo unos minutos. No requiere procesos de configuración complejos.

Habla su idioma

Disponible en más de 35 idiomas, Plone fue diseñado desde el inicio para gestionar contenido multilingüe. Incluye chino, japonés, e incluso idiomas con escritura de derecha a izquierda, como el árabe o el hebreo, de forma fácil.

El niño más bueno de la clase

El equipo de Plone incluye expertos líderes en usabilidad que han hecho que trabajar con Plone sea fácil y productivo.

A todo el mundo le gusta Plone

"Plone fue el ganador del premio del laboratorio de eWeek. Este producto de código abierto es de una de las mejores soluciones para los portales e intranets de empresas".

eWeek, Número Abril de 2006

Amigable al usuario

No estorba y le deja escribir

Plone incluye un potente editor gráfico de texto que permite dar formato al texto e insertar imágenes y enlaces. Si está acostumbrado a trabajar con programas de ofimática, se sentirá cómodo con él.

Buscador de texto completo al instante

Todo el contenido está disponible inmediatamente para realizar búsquedas, incluso documentos Word y ficheros PDF. El sistema de búsqueda en vivo (LiveSearch) muestra los resultados a medida que se teclea la palabra o frase. Pruébelo en la casilla de búsqueda en este sitio.

Escalado de imágenes automático

Al subir una imagen, automáticamente se redimensiona a varios tamaños, lista para utilizarla en sus contenidos. No es necesario Photoshop.

Obtenga la mejor apariencia

Es fácil cambiar el aspecto de Plone. Simplemente puede integrarse con su imagen actual, o le permite crear un nuevo estilo totalmente propio.

Potente

Potente motor de flujo de trabajos (workflow)

Haga que los procesos de su negocio formen parte del flujo de trabajo del documento — complementado por una gestión de la seguridad a prueba de errores.

Velocidad y escalabilidad

Plone cuenta de serie con capacidad de realizar clústers e integrarse inteligentemente con proxys de caché. inteligente de caché proxy.

Seguridad y flexibilidad

Un modelo de seguridad sofisticado, basado en roles, da seguridad a sus contenidos. La arquitectura sandbox de Plone asegura que, incluso si su sistema estuviera comprometido, los intrusos no tendrán acceso a su servidor o a su red.

Sindicación y agregación

Carpetas inteligentes y actualizaciones inteligentes. Plone produce automáticamente noticias RSS desde carpetas, resultados de búsqueda y más — la manera ideal de permanecer en la cima de la explosión de la información y personalizar la entrega de información.

Compatible con los estándares

Accesibilidad

Reúne o supera los estándares de accesibilidad de la Sección 508 del Gobierno de los Estados Unidos y WAI-AA de W3C para personas con alguna discapacidad motora o con dificultad de lectura. Todo el uso de Javascript tiene un modo alternativo que funciona en cualquier navegador.

Excelente visibilidad en los motores de búsqueda

XHTML válido 100% y CSS mantienen una buena relación con los motores de búsqueda y los navegadores. Los sitios Plone están constantemente bien clasificados en los resultados de búsqueda en Google.

Juega bien con otros

LDAP, SQL, SOAP, Web Services (WSDL) y WebDAV — Plone trabaja con todos ellos.

Autenticación basada en agregados

Fácil integración con LDAP, Active Directory y bases de datos SQL. Diga un nombre y seguro que Plone puede dialogar con él.

Asistencia

Asistencia mundial

Si usa la documentación online, listas de correo y chats — u otros servicios de los cientos de empresas de todo el mundo que dan soporte Plone — nunca estará solo.

Código abierto, estándares abiertos

Plone está disponible bajo la misma licencia de código abierto que Linux, y usa el lenguaje de programación Python y el servidor de aplicaciones Zope, ambos también de código abierto. Esto evita dependencia del vendedor, costes de licencias, y le da un futuro previsible — y la libertad de innovar.

Extensa documentación, en prensa y online

Actualmente, hay cinco libros sobre Plone publicados, que ha sido traducidos al alemán, japonés y algunos otros idiomas.

Innovador y extensible

Hay disponibles cientos de productos adicionales — foros, gestores de incidencias, blogs y herramientas de colaboración.

Maduro

Protegido y maduro

Plone existe desde hace más de cinco años. La organización sin ánimo de lucro Plone Foundation es la propietaria y protege la propiedad intelectual y las marcas. Plone también tiene respaldo legal de los expertos del Software Freedom Law Center.

En buena compañía

Organizaciones diversas como NASA, Oxfam, eBay, Trolltech, Nokia, Utah State University, la CIA y Novell utilizan Plone para la gestión de contenidos. Nos encantaría daros la bienvenida a la comunidad Plone.

Plone es su arma secreta

Tanto si se usa para la intranet de una empresa como para un sitio web de una comunidad, Plone cumple.

Fuente


Escrito con el Navegador Flock


Tags: , , , ,

lunes, agosto 03, 2009

Gestión de alcance en Scrum

La adopción de prácticas ágiles para el desarrollo de software requieren muchos cambios en la organización, tanto a nivel cultural, de roles individuales y procesos. A medida que la organización va migrando hacia Ágil, las personas deberán poder gestionar este cambio.

En este artículo veremos los cambios esperados en los diferentes roles para una organización Ágil, junto con técnicas para manejar mejor la transición desde una Cascada tradicional hacia metodologías Ágiles.

Introducción

El enfoque Ágil se basa en objetivos de proyecto a corto plazo. A diferencia del modelo en Cascada, en Ágil se producen piezas funcionales de software cada 2-4 semanas. Este sistema asegura la motivación del equipo y la satisfacción del cliente, con ciclos frecuentes de inspección y adaptación. Ágil tiene la habilidad de repensar las posiciones de las personas y crear un ambiente en donde logren la máxima eficiencia y el máximo potencial individual, logrando así una estrategia de desarrollo de software en la cual se justifican los cambios asociados con sus resultados: Ágil es un enfoque económico y orientado a los resultados para el desarrollo de software.

Adoptar Ágil requiere de cambios considerables en la organización en la cultura corporativa, en los roles y en los procesos. A medida que una organización va migrando a Ágil se hará necesario poder manejar los cambios. En este artículo cubriremos los cambios que ocurrirán en los siguientes roles de la organización:

  1. Cliente
  2. Gerente de Producto
  3. Gerente General
  4. Gerente de Proyecto
  5. Desarrolladores
  6. QA

Es importante notar que no toda la información siguiente aplica a cualquier organización, ya que cada equipo trabaja distinto y tiene diferentes capacidades.

Cliente

Con los proyectos tradicionales en Cascada, los cliente usualmente se mantenían a distancia y sólo se involucraban al principio y al final de un proyecto. Nueve de cada diez veces, el equipo de desarrollo intentaba que el cliente fuera sincero y directo. Le dejábamos en claro que cualquier cambio luego del inicio del proyecto requiere un proceso de control de cambios y penalidades. Después de terminar la codificación, que podía ocurrir varios meses después del inicio del proyecto, entregamos el código para descubrir "lo que salió mal". No es necesario decir que este enfoque es una receta para el desastre.

En los proyectos Ágiles, el cliente necesita estar mucho más involucrado en todo el proceso de desarrollo. De hecho, los proyectos Ágiles esperan el cambio, y siempre es bienvenido el feedback del cliente.

  1. Los clientes tienen que participar y brindar feedback en todos los puntos de "inspección y adaptación". Esto minimiza el riesgo y le brinda más opciones al cliente y a los interesados. Nota: en los proyectos XP, es obligatorio que el Cliente forme parte del equipo.
  2. Los clientes tienen que trabajar con el Dueño del Producto para definir historias de usuario y detallar dichas historias durante las reuniones de planificación.
  3. Los clientes trabajan con el Dueño del Producto para priorizar el backlog.
  4. Los clientes y los interesados participan en las demos de los sprint y, dependiendo en la relación entre el cliente y el Dueño del Producto, el Cliente puede participar en la retrospectiva del sprint.

Gerente del Producto

Los Gerentes de Producto también tienen cambios. Para empezar, el título cambio de "Gerente del Producto" a "Dueño del Producto". Pero eso no es todo. En un entorno tradicional, los Gerentes de Producto son la "entrada" y "salida" . Además de sus tareas de marketing específicas, los Gerentes de Producto suelen ser responsables por el Documento de Requerimientos del Producto. Por otro lado, los Dueños de Producto son la voz del cliente. Migrar de un Gerente de Producto a un Dueño del Producto en proyectos Ágiles requiere los siguientes cambios en tareas y responsabilidades:

  1. El Dueño del Producto es un participantes activo del equipo. Son los responsables por la dirección del producto y las prioridades del proyecto.
  2. El Dueño del Producto debe estar presente en la planificación del Sprint. El Dueño del Producto tiene la primer parte de la reunión de planificación, y es responsable de definir los objetivos del Sprint y también detallar la funcionalidad de cada historia de usuario planificada para ese Sprint.
  3. El Dueño del Producto es responsable de crear, mantener y priorizar el backlog del producto.
  4. El Dueño del Producto tiene que estar disponible para el equipo en todo momento. Se puede debatir si el Dueño del Producto está presente en todas las reuniones diarias, pero mientras más involucrado esté el Dueño del Producto, habrá más probabilidades de éxito.
  5. El Dueño del Producto también es responsable en parte por definir el criterio de pruebas de aceptación y, en este aspecto, es también responsable por la calidad del producto - especialmente porque este criterio de pruebas de aceptación le permite al equipo de desarrollo construir con calidad desde el principio.

Por lo tanto, como Dueño del Producto, hay que estar preparado para estar más involucrado en el día-a-día y ensuciarse las manos.

Gerente General

Como los equipos Ágiles son auto-gestionados, ¿en dónde queda el gerente general, y cuál es su rol?

  1. Los gerentes tienen que estar disponibles para actuar como apoyo al equipo, especialmente si el Gerente tiene la experiencia apropiada - no hay igual para su experiencia. Es por esto que Toyota usa al Jefe de Ingenieros como su Dueño del Producto. Este apoyo puede hacer que los equipos eviten errores y por lo tanto ahorren tiempo.
  2. Los gerentes tienen que estar presentes para ayudar con las tareas difíciles. Por ejemplo, tienen que asistir al Scrum Master a eliminar GRANDES impedimentos que requieren que la gerencia se involucre (como ser, aprobar un presupuesto para seguir avanzando).
  3. Especialmente los equipos nuevos necesitan apoyo y dirección de la gerente para que el proceso Ágil pueda avanzar en la organización. Los gerentes tienen que estar con el equipo para mantener el rumbo hacia Ágil. Es muy facil que los equipos vuelvan a los viejos hábitos.
  4. Los gerentes tienen que actuar como "coach", asistiendo a los miembros del equipo con su plan de carrera, revisiones de rendimiento, capacitaciones y organización de capacitaciones.
  5. Los gerentes deben enfocarse en iniciativas estratégicas de largo plazo para la organización (cómo gestionar amenazas competitivas, incrementar las ventas, reducir costos, etc.)
  6. Basándose en estas iniciativas estratégicas, los gerentes tienen que trabajar de cerca con el Dueño del Producto para definir y priorizar las historias "Épicas" y crear mapas de ruta de proyecto a largo plazo.

Gerente de Proyecto

Scrum directamente se quita de encima el rol tradicional de "Gerente del Proyecto". Entonces, ¿a dónde van estos empleados? Lo más frecuente y natural es que los Gerentes de Proyecto hagan una transición hacia Scrum Masters. Sin embargo, muchos buenos Scrum Masters provienen de Desarrollo y QA. Créanme, el rol del Scrum Master no es ni remotamente parecido al del Gerente de Proyecto. Por lo tanto, es importante que el candidato a Scrum Master adquiera capacitación.

  1. Para empezar, el Scrum Master tiene que aceptar el el equipo es dueño de la agenda, así que no más actualizar los viejos Gantts del MS Project. En cambio, hay que sentarse e inicialmente alentar al equipo para que mantenga actualizadas sus estimaciones diarias.
  2. El Scrum Master se asegura que se siga el proceso de Scrum, que todos entienden Scrum y cómo funciona.
  3. El Scrum Master debe quitar impedimentos, o asistir en quitar impedimentos, lo más rápido posible.
  4. Se asegura que el equipo se mantiene en rumbo, recordandole al equipo el objetivo del Sprint en cada reunión.
  5. Organiza los Scrums diarios (una reunión diaria en donde todos dicen lo que hicieron ayer, lo que van a hacer hoy qué impedimentos tienen), y se asegura que se realice en el mismo lugar a la misma hora.
  6. Se asegura que todos los detalles de Scrum, y en particular los puntos de inspección y adaptación, se tomen seriamente y sean usados de la manera para la cual fueron diseñados. Esto es lo que le permite al equipo mejorar Sprint a Sprint.

Desarrolladores

A los desarrolladores les encanta hacer las cosas bien, no les gusta tomar atajos. No les gusta que los fuercen a deplegar código que saben que no es del todo bueno. El cambio más grande que un desarrollador puede esperar de un cambio hacia Ágil (Scrum + XP) es que se incrementa al máximo la disciplina técnica.

  1. No se estiman más las tareas de forma individual. Esta actividad, quizás la más dificil, se hace en equipo usando, preferentemente, planificación de poker. Como resultado, obtendremos mejores estimaciones. Además, tenemos una responsabilidad compartida por una mala estimación.
  2. Debemos aprender a programar en parejas. Asumiendo que se estén implementando las prácticas de XP (muy recomendable), van a estar haciendo esto muy seguido. Es un cambio mental enorme que los desarrolladores tienen que hacer porque, por primera vez, están abriendo su código para ser revisado por un par. Esto signifca ser criticado cada a paso. Al principio resulta dificil, pero los beneficios son enormes; está garantizado que uno será mejor programador. Se produce código de más calidad y más mantenible.
  3. Ya no se tira código para que después los testers encuentren bugs. Ágil se basa en la premisa de salida sustentable, y para lograrlo es imperativo que la calidad se construya desde el principio. Deberá aprenderse a escribir pruebas unitarias y aprender un montón sobre TDD. Aquí es donde aparece el desafío técnico para producir el mejor código posible, con la mejor calidad. Y los beneficios son enormes.
  4. Los desarrolladores participan en el proceso completo. Esto genera una nueva perspectiva de las cosas, ya que se forma parte de las historias inicial. En consecuencia, podremos escuchar problemas directamente del Cliente/Dueño del Producto, ya que están allí para dar detalles durante las reuniones de planificación del Sprint. También se participa de la retrospectiva para reflexionar sobre lo que ocurrió, lo que salió bien y mal, y así implementar mejoras sprint a sprint.
  5. No hay que realizar esfuerzos desmedidos continuamente. De hecho, si seguimos Scrum, nunca debemos esforzarnos desmedidamente. La velocidad mantiene el ritmo sustentable del equipo, que gobierna cuánto trabajo en progreso hay en un momento dado. Los equipos pueden desplegar a producción cada dos semanas, sin error. Esto se logra optimizando la velocidad y el trabajo realizado. Podemos aprender un montón del pensamiento Lean y del Sistema de Producción de Toyota (TPS).
  6. Si se sigue el proceso, no habrá que preocuparse por trabajar fines de semana continuamente, o código malo. En cambio, al final de cada Sprint, podremos sentirnos orgullosos de lo producido, y nunca más querremos trabajar de otra forma. Esto requiere que todos los interesados estén involucrados en este nuevo proceso desde el principio (un pre-requisito para una implementación Ágil exitosa).
  7. Al finalizar cada Sprint, tenemos la oportunidad de demostrar lo que realizamos. Este es el momento de brillar (en vez de ocultar), a diferencia de proyectos en cascada donde nunca sabemos dónde puede aparecer el próximo bug.
  8. Trabajamos en equipo y alcanzamos cada hito en equipo. No hay "yo", sino "nosotros". Buscamos oportunidades para ayudar a los miembros del equipo en lo que necesiten.

Testers de QA

Los proyectos en Cascada, al atrasarse, suelen recortar tiempo de QA. Este escenario cambio con las metodologías ágiles.

  1. QA participa desde el inicio de cada Sprint. ¿Qué valor puede dar un tester en estas fases tempranas del proyecto? Al participar en las reuniones de planificación del sprint, vamos a informarnos sobre las historias planificadas. De hecho, QA está involucrado en elaborar las historias de usuario. Por ejemplo, ayuda a definir el criterio de pruebas de aceptación para las historias. Esto ayuda a los Desarrolladores a entender lo que se necesita para pasar las pruebas. Como resultado, se mejora la calidad del código y también la "utilidad" del código (qué tan cerca está del requerimiento del usuario).
  2. Estaremos involucrados en la creación de pruebas unitarias. Este es una forma importante por la cual los testers pueden mejorar sus habilidades. Esta es un área en donde los testers pueden agregar mucho valor al proceso con su marco de pensamiento estilo "cómo puedo romper esto".
  3. Deberemos automatizar la mayor cantidad de pruebas funcionales. Como resultado, contribuiremos con la efectividad general del equipo y su productividad. El pensamiento Lean sugiere que los equipos necesitan estar enfocados en construir con calidad y minimizar los desperdicios, ya que esto es lo que más afecta a los ciclos de tiempo. Entonces, al escribir pruebas automatizadas, estamos contribuyendo a la calidad general del código y como resultado reducimos el tiempo de ciclo total.
  4. Seremos un miembro respetado del equipo en vez de un ciudadano de segunda que "detiene la línea de producción". Por ejemplo, cualquier bug que se encuentra incluso en etapas tempranas del producto debería resolverse ni bien se encuentra. Ágil resuelve los problemas de la gestión de proyectos tradicionales construyendo un equipo cohesivo y tratando a cada área funcional como desarrollo. De hecho, Scrum sólo hace referencia a "Desarrolladores" del proyecto (por ejemplo, si sos un tester dentro de un proyecto Scrum, sos otro Desarrollador que tiene entregables en el backlog del sprint).
  5. Como los Desarrolladores escriben pruebas unitarias, no se recibirán más código con muchos errores. Ahora podemos enfocarnos en aspectos más importantes de las pruebas, como ser pruebas de frontera, y en la automatización de las pruebas.
  6. Las prácticas de Scrum/XP y Lean confían en que todo el código que se entrega al final del Sprint está TERMINADO (con pruebas unitarias, funcionales, e integrado). Entonces tendremos tiempo para completar cada una de estas pruebas en cada Sprint ya que todo el trabajo (incluyendo el testing) está contando dentro de la planificación del Sprint (a diferencia de tener, por ejemplo, las últimos 3 semanas dedicadas al testing de un proyecto).

El testing maduró mucho desde las metodologías Ágiles, y ahora son miembros mucho más respestados en la industria del software. Ahora el testing es esencial para el desarrollo de buen software qeu asegure que funcione como se espera. Con conceptos como TDD y BDD, los esfuerzos de testing cambian de un enfoque tradicional "al final" del proyecto hacia un enfoque desde "el inicio" del proceso, y como resultado, se construye la calidad desde el comienzo.

Conclusión

Ágil adapta el entorno de desarrollo para sacar a relucir todo el potencial de los equipos y trasladarlo hacia ciclos de desarrollo increíblemente eficientes. También alienta la colaboración efectiva y productiva de las personas, eliminando las jerarquías corporativas en favor de equipos funcionales. Una migración a Ágil requiere un esfuerzo coordinado y el deseo de adoptar cambios a través de todos los aspectos en los equipos de desarrollo. Al principio, los cambios asociados a implementar Scrum parecen épicos. También es fácil distraerse con los aspectos técnicos del cambio, en vez de hacer foco en las bases: una reestructuración del proceso de desarrollo de software para hacerlo más eficiente.

Fuente: DosIdeas