El buscador de profesionales a domicilio

Archive for the ‘Test Driven Development’ Category



27
Jan

Un solo valor de retorno

Hay un mal que se esta extendiendo por la aplicación en las últimas semanas. Es el ResponseDTO. Es un objeto plano, tiene un campo "success" de tipo boolean y un campo "message" de tipo string. Debía llamarse Response pero colisionaba, así que se quedó con un mal nombre. Si le hubiesemos llamado ControllerResponse seguramente no se hubiese usado en las otras capas de la aplicación porque hubiese dado más pistas a quienes lo fuesen usar, de que su lugar es la capa controller. Sin embargo se ha colado en muchas capas de backend y no es una buena práctica:

Los metodos y funciones deben devolver un solo resultado y en ocasiones, ninguno (void). ResponseDTO se puede considerar "un solo resultado" cuando los campos "success" y "message" se necesitan el uno al otro, tal que no tiene sentido el objeto sin los dos campos. Es decir cuando el objeto es lo más atómico que la operación puede devolver. ResponseDTO se ideo para enviar a cliente (js) respuesta a determinados comandos que solicita al servidor pero no debería usarse en las otras capas de la aplicacion.

¿Dónde lo usamos mal? Tenemos métodos con un nombre interrogativo que denotan retorno boolean y sin embargo devuelven uno de estos ResponseDTO:

  • IsExistingUser
  • DoesPolicyExists
  • IsValidInput

Para cualquiera que lea la API, no es intuitivo. ¿Para qué sirve el "message" del objeto cuando el método "IsExistingUser" retorna? Para nada.

En la validación, puede tener sentido este objeto response dependiendo del contexto: Si el error de validación puede considerarse una circunstancia excepcional, entonces lo mejor es lanzar una excepción que alguien de nivel superior recogerá. Por tanto, sobra el objeto response ya que la excepción llevará el mensaje de validación particular. Si un problema de validación no se considera una circunstancia excepcional, entonces puede estar bien devolver el response con su success puesto  a false y su mensaje concreto.

Más sitios donde lo usamos mal: Métodos que disparan acciones hacia fuera de nuestro sistema

  •  SendEmail
  •  SaveUser

Los métodos que provocan acciones que salen de los límites de nuestro código (acceso a BD, a un servidor de correo, etc) no pueden garantizar la correcta consumación de la acción. Por tanto, jugar a devolver boolean para exito o fracaso es engañarnos.
Es preferible un método void que funciona sin hacer ruido cuando todo va bien y que lanza excepciones cuando se encuentra con una situación inesperada. Por ejemplo, el método que solicita el envio de un email, puede defenderse de excepciones que provoque la libreria de SMTP y traducirlas en excepciones de nuestro dominio, tales como EmailSendFailure (una excepción nuestra que hereda de ApplicationException).

¿Y es tan grave que usemos el ResponseDTO? Sí que lo es porque el código que consume esos métodos se convierte en spaguetti:

var isNotValidData = !InputValidator.ValidateUserData(
                          policyHolder.Person).success;
if (isNotValidData)
{
	response.message = Strings.T("Los datos son incorrectos.");
	return response;
}

Del método "ValidateUserData" sólo nos interesa el campo "success", el mensaje lo está generando el llamador. No sólo es raro de leer sino que es un coñazo a la hora de escribir tests de interacción. Cuando queremos que en un test de colaboración, este método devuelva falso, tenemos que especificar que devuelva un objeto con un campo a falso. Si fuera boolean, no tendriamos que especificar nada porque el valor por defecto sería false. Esto va al hilo del posts de los tests de interacción limpios.

En el caso de métodos de acción como el envio de email, es incluso peor porque quien consume el método pensará que con un resultado verdadero el email ha llegado a su destino, como si eso lo pudiesemos asegurar de alguna manera.

Para saber qué debe devolver un método, este debe tener una única responsabilidad y debemos saber cual es. Y la mejor manera de saberlo, para mi siempre es escribir el test antes que el código.

 

26
Jan

Cleaner interaction tests

Note: this post will probably evolve, the text will be updated as I need it.

In order to write cleaner interaction tests (those which use test doubles; mocks, spies, stubs) you should understand how your test doubles framework works. Interaction tests can be extremely difficult to read and maintain and very fragile if you don't pay enough attention. We will review Mockito, Moq, Jasmine and pyDoubles.

Mockito and Moq create a double object by inheriting the original and overriding its methods. pyDoubles uses interception rather than inheritance. Jasmine is different because it does not double the whole object, but just the method you spy on. So there is a big difference: Mockito, Moq and pyDoubles replace the whole object while Jasmine replaces just one method.

So Jasmine leaves space for a bad testing practice: Spy on one method of the object while testing other method of the same object. Interaction tests are intentded for object collaboration. Testing that one method calls another method within the same object is not recommended. It means that the object has more than one responsibility or that you want to know more about the object's inner behavior than you should, so you are breaking encapsulation. This is not a Jasmine problem, the problem is yours if you don't use the tool properly.

There are three primary reasons to replace method calls on collaborators:

  1. You want to avoid a database call just to keep the test unit fast and repeatable (stub the method - use a stub object)
  2. You want the method to return some value to simulate the response (stub the method - use a stub object)
  3. You want to make sure that a call is made (spy or expect the call - use a spy or a mock object)

For case numer 1, you don't have to specify the returned value. Just use the stub object and let the framework return whatever it wants. Mockito and Moq, return the default value for the method, when no other behavior is specified:

  • If the method returns an integer, a call to that method in the stub object, will return cero (default value for integers)
  • If the method returns an object (reference type), a call to the stub method will return null (default for objects)
  • False for booleans and so on...

However, be careful with Moq because in C#, if the original method is not virtual (contains the virtual keyword), Moq can't stub it out, so the original will be called. Moq fails if you specify a behavior on that method but if you don't, it calls the original instead of returning the default value.

pyDoubles always returns None no matter the method signature.

For case numer 2, you define what the returned value should be. Using "when" in Mockito and "Setup" in Moq.

For case numer 3, you verify that a call was made:

  • Mockito: verify(double).method();
  • Moq: double.Verify(x=>x.method());
  • pyDoubles: assert_that_method(double.method).was_called()
  • Jasmine: expect(double.method).toHaveBeenCalled()

You might want to know what parameters were passed in too. In this case you can use Matchers in Mockito, Moq and pyDoubles.

Moq sample:

userRepository.Verify(x => x.SaveNewUser(
        It.Is<Person>(
        p => p.PersonalIdentificationCode == "TEST_CODE")));
 

pyDoubles sample:

assert_that_method(double.method
         ).was_called().with_args(obj_with_fields({
                            'id': 20,
                            'test_field': 'OK'}))

For Mockito samples I am waiting for my friend @regiluze to write a post on it :-) I will link it here when written.

Jasmine sample:

spyOn(double, "method").andCallFake(function(){
      expect(arguments[0].name).toEqual("Carlos");
});

Test collaborations one to one:

If the object under test has more than one collaborator, tests can be really hard to understand. I recommend expressing every collaboration in a single test:

  • A talks to B (test 1)
  • A talks to C (test 2)
  • For test1, B will be a spy o mock (you use Verify at the end). Also for test1, you don't care about C, C is just a dummy. Calls to C don't need to be configured in the double, let the framework return the default value.
  • For test2, C is the spy or the mock, you verify interaction between A and C, and do't care about B. Calls to B don't need to be configured, let the framework return whatever.
  • For test1, if the value returned by C, is necessary for the collaboration between A and B, then Ok, specify the stub result for that call to C, and verify on B.

Group the tests by setup:

Should I have a test class for every class in the production code? NO.  Tests must be grouped by their setup. This is, put those which have the same arrangement in the same test case (test class). If there are two or more interaction tests in a class, the creation of the SUT and the doubles, should not be in every test. It must be in the setup, along with the injection (doubles, are injected to the SUT as collaborator). So, if you find yourself injecting the test double to the SUT in more than one test, watch them again carefully.

 

 

16
Jan

Mockito Vs Moq

Don't be confused, the title is just to get your attention. This is not a benchmark between Mockito and Moq. I need to  explain some differences to my teammates so that the transition between Mockito and Moq is softer for them.

Typical way to stub out a method call with mockito:

when(colaborator.method(argument1)).thenReturn(whateverIwant);

Same with Moq:

colaborator.Setup(x => x.method(argument1)).Returns(whateverIwant);

Obviously, the mockito way is nicer. I believe this is because of Java capabilities but I am not sure. I would like to dig into mockito's source code to see how is this possible. I will do it and blog about it soon. I used to think that it was because of the kind ot late binding supported by Java, but I am not sure.

Moq uses a lambda expression (anonymous method inlined) to tell the framework which method and how is expected to be called). The reason I use "x" for the object in the anonymous method is because it refers to "colaborator" itself so there is no point in adding more names.

The other important difference relates to the "virtual" keyword in C#. Methods in C# are final by default. You can't override them unless they contain the keyword "virtual" on its signature. Both, Mockito and Moq create test doubles by subclassing on runtime, overriding methods and implementing the fake behavior on them (as far as I know). So, if the method you want to stub is not virtual, Moq will throw a runtime exception. If it is not virtual but you don't specify any fake behavior on it, it will not throw exceptions, but worse, it will call the actual implementation. So you might be hiting the database in your unit tests inadvertedly. What I do, is that all my methods are virtual by default (I write "virtual" on their signature).

There will be more posts on this topic :-)

19
Dec

Javascript, an acquired taste

You hate it, you love it

You start hating it but you might end up having so much fun with Javascript. It takes time to acquire the taste and enjoy the powerful capabilities that annoy you at the beginning. This is my experience learning this popular language.
Take into account that my opinion is based on just a few months of experience with Javascript as a language, not just a tool to manipulate the DOM (html and css). It will probably change along the journey.

The white box

Being used to languages like Python, I'd say Javascript is a white-box language while Python is a black-box one. That is, you don't really need to read books to start coding in Python, you just see some example code, try some lines and usually its execution behaves as you expected. It feels so natural. That is not the case of Javascript, its rules are not natural at a first glance. In fact, you have to know very well how the interpreter makes decisions. If you make a mistake writing some code that wouldn't compile or would raise an exception on other programming languages, Javascript will instead try to execute the code. And will probably traverse all the execution path. Because it doesn't fail, this behavior can be very confusing and hard to detect. You wish the interpreter to tell you that, you made a mistake and you probably didn't want to write what you did, you don't want the execution to continue. That is the feeling at the beginning. On the other hand, as time goes by, these capabilities turn out to be so powerful in terms of implementation choices and performance tuning.
Unfortunately coding for performance tuning leads to code that is hard to understand and maintain.

TDD is a must

We've been pairing and test driving our Javascript code these months using Jasmine.  I feel that the impact of BDD on Javascript is bigger than on any other language. It's mandatory. I don't want to write a single line of production code if there is no failing test asking for it. Because Javascript forces me to be smarter than I am sometimes and ocuppies part of my mind with subtle implementation details that moves me away from writing code that expresses the business domain, the semantic of the actual business problem to solve.
If I don't write a test, a specification that clearly states what I expect the code to do and see it pass, I can't bet that it will work just by looking at the production code. It would feel like gambling.

There is a tone of patterns to avoid tipical Javascript mistakes. There are many books on the subject. Experts advise you techniques like, "check the type of the arguments the function receives, to make sure you get what you expect". But then they tell you that "instanceof" operator might not work if the inheritance wasn't implemented properly. It is overwhelming. I tell you a secret... you don't need to master all those patterns if you test drive your code! You don't have to worry about all possible usages of your code if it's you or your team who are going to consume it, because the specifications are already thought, written and are executable.

I always prefer "duck typing" than asking for the type of the arguments. I usually prefer to let Javascript evaluate conditions using its coercion rather than using strict  operators like "===" or "!==". Because if you write code for humans, it is better to say:
"if (userExists)"
than
"if (userExists === true)".

So the approach and the concerns are totally different when you test drive the code. The productivity gain is brutal. Javascript is too expensive to work with if you can't guarantee all the time, that your code functions as you inteded it to be.

If for some reason I would not be able to develop with BDD, I would code with Coffescript rather than Javascript :-)

The approach is totally different if you are writing a framework. Frameworks are too general, they are horizontal, not vertical so there is no business semantic on them. So yes, for frameworks you should be a Javascript power ranger.

OOP or Funtional?

Javascript is not a classical objet oriented language. There are no classes. However is a great language for object oriented programming! Don't be confused with this. If you know the object oriented paradigm, you just need to know how to implement polymorphism, composition and so on. The discussion on "there are no classes, there are prototypes", is superfluous. It is an implementation detail I don't care about. I don't think that is really important because I can express behavior with objects and model the domain the same way I would do it in Java. Rather than using "class" and "extends" I would use "constructor stealing along with prototype chainning". But it's the same tool :-)

On the other hand, javascript is a great language for functional programming too :-) It is actually more used as a functional language than as an OOP one. It is very common to pass functions as parameters and things like that.

You can approach different paradigms with Javascript. My advise is to not mix them together though.

Programming the UI is fun again!

I used to write desktop applications using Delphi, pyGTK and Windows Forms at the beginning of the past decade. When the web started getting mainstream, it was sad to say goodbye to all the best practices learned all those years. Used to the power of event oriented programming, rich components, data binding, and design patterns in general, developing for the web felt a step back. During the past decade there have been many attemps to mimic the old desktop in the web; portlets, asp webforms, and so on. None of them made developers happy, so the Model-View-Controller (MVC) pattern came to the rescue. However, dealing with the UI is still something developer don't really use to enjoy. DOM manipulation has been a pain in the ass with every browser having different behavior and API. I've been trying to avoid it until now and, to be honest, I am happy to not have invested my time fighting with problems that jQuery handles for me nowdays.

Now, ECMAScript 5 is supported in all major browsers. jQuery and other frameworks make life easier. And there is something that we didn't have in the old desktop programming: the chance to programmatically interact with widgets (UI controls or components). Well there are some frameworks for that in the native desktop, by they came late. This means that we can write automated tests for UI behavior!

So now, we have the chance again to use event driven programming, to really implement patterns like the "observer" and many others. And we can test drive all of them!
We can develop semantic components that add domain knowledge inside UI widgets and make the user experience way better. There is no need for intrusive frameworks that tell us exactly all the layers to be used and how. Everything is ready to craft the code to make it express as much human knowledge as possible.

So we are taking the chance.

No need for MVC frameworks

In the first two weeks of the project we started using Backbone. In the first spike, we used the whole framework. A bit later, just the models and collections. Nowdays, we have completely got rid of it. It is a great framework, but we don't need MVC frameworks anymore on the client side because they are more restrictive than we need. We don't develop "screens", we try to create "smart components" that can be reused and provide a different level of abstraction. The screen is just a place holder for components that can be injected. With the rich UI programming that Javascript give us today, the paradigm has changed. It is time to retrieve practices from 15 years ago mixed with best practices learned in the latest years. I wouldn't port or copy exactly what we have been doing recently.

 

1
Dec

Don’t let mockito confuse you

The new version of mockito comes with a new method: spy. Very useful feature but... bad name!

The mockito's "mock" method creates already a spy object. The "spy" method creates a "proxy" or "proxy spy" object. Totally confusing, isn't it?

The "mock" method is not really awful, because you can also use the double as a mock or just a stub, and it is common to use the name "mock" for all kind of doubles, although still confusing. The benefit from naming the double properly is that it helps programming by intention, which is a big part of Test Driven Development.

I would rename "mock" to "double" and "spy" to "proxy". Anyway, don't forget that, when using the mockito's "spy" method any single call that you don't explicitly stub, will reach the actual object. It is really useful to work with legacy code, in fact, we implemented it in pyDoubles, but using the method "proxy_spy".

Just make sure you understand what kind of test double you use and why. That is what matters in the end :-)

30
Jul

Erlang en la #kataplaya

Hoy decidimos desafiar a los #katayunos haciendo una #kataplaya. Una kata a 50 metros del mar, en un bonito pub playero. kataplaya1Aprovechamos el profundo conocimiento de Joel Reymont (@wagerlabs) del lenguaje Erlang y nos pusimos con el String Calculator en este lenguaje. Aquí se ve el código de la primera iteración, hecha con el mejor TDD que pudimos y un segundo snapshot de código demostrando potencia de Erlang pero dejando a un lado TDD.

Erlang es un lenguaje funcional, que NO está basado en el paradigma de la orientación a objetos. Debo confesar que me ha gustado mucho. Yeray Darias y yo hemos disfrutando viendo nuestras primeras lineas de Erlang :-)
Me ha gustado más que Lisp y Prolog, aunque ya hace años que no uso ninguno de los dos, pero este parece más limpio (no hay miles de paréntesis juntos). Trabajando con un experto al lado como Joel, hemos podido ver rápidamente por qué Erlang tiene muy buena pinta para escalar. Por un lado, se maneja bastante a bajo nivel, lo que da sensación de ahorrar muchos recursos. Por otro, el estado no se guarda, se procesa. Y al menos en lo que hemos visto hoy, la gestión de la memoria es sencilla, no es como C. Por otro lado, la posibilidad de diseñar una funcion en distintos bloques dependiendo del patterng matching de los argumentos de entrada, evita bastantes bloques condicionales y pareciera que nos ayuda a escribir código más limpio.No te fies de este post como una review seria de Erlang, son sólo mis impresiones despues de dos horas de code kata, en una kata que además es trivial.

A ver para cuándo la siguiente #kataplaya :-)

16
Jul

The stubbing spy

Do you really need a stub or do you better use a spy? Or is it a spy object with some stubbed specifications? Let's see some examples using pyDoubles:

You can choose a stub object to prepare the scenario and then, assert on the returned value of the system under test.

 
    def test_using_a_stub(self):
        USERID = 20
        collaborator = stub(Collaborator())
        when(collaborator.one_arg_method).with_args(
            USERID).then_return(SUCCESS)
        sut = SystemUnderTests(collaborator)
 
        result = sut.exercise_method()
 
        assert_that(result, equal_to(OK))
 

The test above says: "I don't really care what the SUT does internally as long as the returned value is the expected, but it might need help from a collaborator, so I set it up, just in case."
Note the "might" part of the sentence. It is not necessary to specify the possible arguments in the call to the collaborator. This tests is more robust and still serves the same:

 
    def test_stub_simplification(self):
        collaborator = stub(Collaborator())
        when(collaborator.one_arg_method).then_return(SUCCESS)
        sut = SystemUnderTests(collaborator)
 
        result = sut.exercise_method()
 
        assert_that(result, equal_to(OK))
 

Now, let's replace the stub with a spy object, assuming we don't need to specify any stub behavior:

 
    def test_if_arguments_are_important_check_them_out(self):
        USERID = 20
        collaborator = spy(Collaborator())
        sut = SystemUnderTests(collaborator)
 
        result = sut.exercise_method()
 
        assert_that_method(collaborator.one_arg_method
               ).was_called().with_args(USERID)
        assert_that(result, equal_to(OK))
 

The test above means: "The SUT needs to call its collaborator at least once in order to complete the operation. I want to make sure that happens apart from getting the expected value."
Depending on the problem, we can have just one test with the 2 asserts, or maybe 2 tests, with one assert each.

We didn't need to define any stub method, but what if we need it?:

 
    def test_if_arguments_are_important_check_them_out(self):
        USERID = 20
        collaborator = spy(Collaborator())
        when(collaborator.one_arg_method).then_return(SUCCESS)
        sut = SystemUnderTests(collaborator)
 
        result = sut.exercise_method()
 
        assert_that_method(collaborator.one_arg_method
               ).was_called().with_args(USERID)
        assert_that(result, equal_to(OK))
 

We don't tell the stub what arguments is going to receive. That is not important. The stub part is intended to prepare the scenario. The easier the scenario setup is, the better. We do assert on the arguments at the end of the execution.

Conclusion:
If calling the collaborator is a critical part of the action, use a spy and make sure arguments are passed in as they should. If you need to stub out a method in the spy object, do not specify the arguments in the stub definition. In the stub definition, just tell the framework the returned value and later on, assert on the arguments once the system under test execution has finished

Reason: If you specify arguments in the stub definition and also don't assert at the end, you need to debug the failing test to find out that maybe some argument wasn't passed in.
It is more efficient to let the doubles framework tell you what was wrong :-)

10
Jul

Cartel de lujo en la #XPweek

Del 20 al 23 de septiembre de 2011, tendrá lugar la #XPweek en Madrid. Se trata de los dos cursos abiertos de iExpertos, sobre iniciación a TDD y TDD avanzado, donde además veremos otras cuestiones de XP como la programación en pareja y el ciclo de desarrollo de los proyectos. En esta ocasión contaremos con la actuación estelar de algunos de los profesionales más importantes del país:

Alfredo Casado: Estará con nosotros en el curso de introducción (20 y 21) hablandonos sobre legibilidad de los tests. Cómo escribir tests para humanos con la ayuda de herramientas como Hamcrest. Alfredo es uno de los desarrolladores con más experiencia en eXtreme Programming en España. Además es un excelente docente, de hecho, ha impartido clases en varias universidades.

Enrique Amodeo: Estará también el en curso de introducción hablándonos del Principio de única responsabilidad (SRP) y de refactoring de manera práctica. Enrique lleva años practicando XP y liderando equipos de desarrollo. Sin duda una de las figuras más destacadas del país en cuanto a desarrollo ágil y arquitectura del software.

Xavi Gost: En el curso de TDD avanzado, Xavi nos hablará de BDD con Javascript, Jasmine y de arquitectura Javascript. Nos presentará su framework Javascript y tendremos la oportunidad de aprender sobre arquitectura SPI. Xavi Gost es probablemente el más veterano de todos nosotros en prácticas de ingeniería ágiles. Actualmente al frente de BeCodeMyFriend, la incubadora punk.

Alberto Vilches: Alberto es referente nacional en tecnología Grails. Como el framework base para nuestro curso de TDD avanzado será Django, Alberto nos ayudará a entender cómo los conceptos explicados se pueden aplicar en Grails. Nos dará trucos y consejos para sacarle el máximo partido a todo lo que vemos en el curso.

Yo seré docente en ambos cursos y estaré encargado de coordinar la participación de estos grandes profesionales en las distintas etapas por las que vayamos pasando.

Aún quedan plazas libres, escríbenos a info@iexpertos.com para reservar la tuya :-)

8
Jul

TDD: resultados empíricos

Hace poco en una code kata alguien me dijo, ... "y qué ventajas tiene esto de hacer TDD?". Le dije... en nuestro proyecto, actualmente con casi 25.000 lineas de código Python (multiplica x4 si piensas en Java), no hemos necesitado nunca bugtracker. Cuando ha aparecido algun bug, se ha corregido enseguida y vuelto a subir a producción. Podemos hacer una release a producción cada dos días y sólo con una persona de QA, que dedica 10 minutos antes de cada release. No llegamos al continuos deployment por falta de recursos pero estamos muy cerca.
Cuando tenemos que hacer un cambio, lo hacemos en cuestión de horas o minutos y podemos subir a producción con total garantía (98%) de no haber roto nada.
Cualquiera del equipo le puede meter mano a cualquier parte del proyecto.
Lógicamente no obtenemos estos resultados por la practica de TDD en exclusiva, sino por todas las practicas y valores de eXtreme Programming (recuerda que TDD/BDD es una parte de XP).
Y todavía podía seguir enumerando ventajas. Sin embargo, el código de nuestro proyecto no es open source, así que la gente tiene que creernos. Ahora, con pyDoubles, puedes ver los resultados tu mism@:

Resultados empíricos basados en pyDoubles:
En la última release del framework, la 1.2, hemos conseguido compatibilidad total con Hamcrest, el framework más conocido de matchers, para mejorar la legibilidad de los tests. Estratégicamente esto hace que pyDoubles pueda convertirse en un framework de referencia, ya que Hamcrest es muy popular y ahora ambos frameworks encajan perfectamente. Es un gran logro a nivel de negocio, teniendo en cuenta que queremos que pyDoubles sea usado.
¿Sabes cuanto nos ha costado a nivel de desarrollo? 3 horas de trabajo. Puedes ver los commits que se han hecho de la version 1.1 a la 1.2 si quieres mas datos objetivos. Nunca habiamos visto el código de Hamcrest ni habíamos desarrollado pyDoubles pensando en Hamcrest, sin embargo, hemos desarrollo siguiendo SOLID, dejando todo abierto a extensión y cerrado a modificación. El resultado es contundente. Apenas un poquito de esfuerzo para alcanzar un gran resultado.
¿Cuánto nos podía haber costado esto sin hacer bien TDD? Probablemente semanas de trabajo. Probablemente haber tirado medio framework y haberlo tenido que reescribir, con el riesgo de cargarnos por el camino las funcionalidades existentes.
En esta release 1.2 no solo hemos tardado poco, sino que estamos seguros de que no se ha roto ninguna funcionalidad.
¿Cuál es el orden de beneficio de esta forma de trabajar? Dificil de cuantificar pero la sensación es de ser 10 veces más productivos. Entonces ahora ¿es más caro o es más barato hacer un buen TDD/BDD?

No necesitamos convencer a nadie, los datos empíricos van demostrando las ventajas por su propio peso :-)
Olvídate de convencer a tu entorno sobre las ventajas de XP, practica con el ejemplo.

6
Jul

Próximo dojo: el reto XP

El próximo martes 12 de julio, facilitaré un coding dojo en las instalaciones de DECiDE, que llevará por título, El reto XP.

Este evento es totalmente gratuito y las plazas son limitadas. Para inscribirse, está la siguiente url: http://decide.stagehq.com/events/916

El dojo no estará basado en una kata sino que tendrá un formato eliminatoria. Se planteará un reto a los participantes que les ayude a medir su nivel de interiorización de las prácticas y valores de eXtreme Programming. A lo largo de la jornada, algunas parejas irán siendo eliminadas aunque tendrán posibilidad de volver al juego en alguna ocasión.

Como siempre, hay que venir al dojo con el portátil y el entorno de desarrollo favorito instalado. Empezaremos a las 17h y la duración máxima será de 3 horas. Se programará en pareja pero no es preciso venir en pareja.

De nuevo, otro evento gratuito de la mano de iExpertos :-) , con la inestimable colaboración de Decide.

Celadon theme by the Themes Boutique
teeth bleaching
baldness treatment