TDD, SOLID y sobre-ingeniería

Visto 47 veces
Saltar al primer mensaje no leído

Diego Güemes

no leída,
25 sept 2012, 8:03:4425/9/12
a tdde...@googlegroups.com
Hola a todos.

Hace poco realicé con TDD la Kata del String Calculator: http://osherove.com/tdd-kata-1/

El caso es que no se si me estoy volviendo quizás algo paranoico y estoy pecando de sobre-ingeniería, pero llego a crear muchísimas clases al distinguir varias responsabilidades e intentar cumplir el Single Responsability Principle.
  • Responsabilidad de sumar
  • Responsabilidad de parsear la cadena
  • Responsabilidad de parsear delimitadores de la misma
  • Responsabilidad de validar que no haya números negativos
  • Responsabilidad de filtrar números mayores que 1000...
Me mosquea el hecho de crear todas estas clases para un método tan simple que a fin de cuentas solamente suma los números de un string.

Por eso quiero plantear que al intentar cumplir todos los principios SOLID, en concreto el SRP... ¿Es posible que caigamos en algún tipo de sobre-ingeniería?

Por otra parte, cuando realicé la kata iba haciendo tests de la clase principal, al extraer una clase de la misma, moví el código de producción, pero no los tests. Creo que se pueden aplicar dos enfoques aquí:
  • Mover los tests correspondientes a esa otra clase y utilizar mocks para probar el comportamiento e interacción entre los objetos.
  • No mover los tests, puesto que el caso de uso está probado y TDD tiene como objetivo diseñar el software y no obtener la máxima cobertura de tests.
Me interesaría conocer vuestra opinión sobre los dos enfoques o cualquier otro que vosotros utilicéis y no estoy contemplando.

Un saludo y gracias de antemano,

Diego

Enrique Amodeo

no leída,
25 sept 2012, 8:27:1525/9/12
a tdde...@googlegroups.com
Hay varias cosas que suelo tener en cuenta a la hora de avanzar más en SOLID:
a) Tus tests *unitarios*. ¿Son legibles? ¿Sencillos de mantener? ¿Pequeños y enfocados? Si es que no, considera refactorizar tu diseño.
b) Las historias de usuario. Te dan pistas sobre que tipo de cambios funcionales pueden aparecer. Claramente en el caso de la calculadora: si soportas la suma, es probable que tengas que soportar la raiz cuadrada en el futuro, por lo que tu diseño debería soportar añadir nuevas operaciones en el futuro (fijate que esto afecta también al parsing).
c) Lo más importante: timebox. Si no tienes más tiempo/dinero para refactorizar, no lo hagas, no vaya a ser que YAGNI. Siempre puedes hacerlo en el futuro cuando aparezca la necesidad (siempre y cuando le pases estimaciones realistas al cliente).

En resumen tienes que equilibrar SOLID con KISS/YAGNI. Como conseguir ese equilibrio es todo un arte.
Por cierto, cuando vas refactorizando, tienes que hacerlo sobre el código de producción y el de test a la vez. Cuando refactorizas el código de producción es común que tu test pase de ser unitario a de integración, en esos casos deberías refactorizar tu test a varios test unitarios. El test original lo puedes mantener o borrar, segun gusto (yo lo suelo borrar).

Salud !

2012/9/25 Diego Güemes <diego...@gmail.com>

--
Has recibido este mensaje porque estás suscrito al grupo "TDDev" de Grupos de Google.
Para ver este debate en la Web, visita https://groups.google.com/d/msg/tddev-sp/-/wPGkG7imboEJ.
Para publicar una entrada en este grupo, envía un correo electrónico a tdde...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a tddev-sp+u...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/tddev-sp?hl=es.

Angel Java Lopez

no leída,
25 sept 2012, 9:40:0525/9/12
a tdde...@googlegroups.com
Hola gente!

Diego, con respecto a:

Por otra parte, cuando realicé la kata iba haciendo tests de la clase principal, al extraer una clase de la misma, moví el código de producción, pero no los tests. Creo que se pueden aplicar dos enfoques aquí:
    • Mover los tests correspondientes a esa otra clase y utilizar mocks para probar el comportamiento e interacción entre los objetos.
    • No mover los tests, puesto que el caso de uso está probado y TDD tiene como objetivo diseñar el software y no obtener la máxima cobertura de tests.
Bueno, yo opto en general por lo segundo. Pero no entendi tu "obtener la maxima cobertura de tests". Lo segundo lo hago en la etapa de refactor, y si lo hago bien, sigo teniendo maxima cobertura de codigo (no de tests). Supongo que querias decir que en la clase nueva hay metodos que no tienen un test que los llame directamente. Pero no es la idea de TDD. Si la clase nace por refactor, hasta podria ser privada, interna, y no tener test directos.

Lo que si me pasa, cuando es mas que una kata, es que la clase nueva comienza a tener mas responsabilidades al sumarse mas casos de uso y test. Por ejemplo, si surge un Parser como clase nueva, luego de haber armando, digamos, Compiler, posiblemente comience a poner nuevos tests sobre Parser directo, a medida que se vayan sumando mas tests. O que cuando tenga un nuevo test en Compiler, como "ahora compila 'spam[1:2]' como pasa en Python", en vez de encarar toda la resolucion de ese nuevo caso dentro del metodo Compiler.compile(), primero vaya incrementando al Parser con algun test que me diga que aprendio a parsear 1:2 (yo lo llamo un slice).

Creo que la tension entre SOLID y sobreingenieria viene mas por el contexto de estar trabajando en un kata. En un codigo real, SOLID va apareciendo en su justa medida, paso a paso, por tener un ejemplo mas complejo.

Nos leemos!

Angel "Java" Lopez

2012/9/25 Diego Güemes <diego...@gmail.com>

--

Diego Güemes

no leída,
26 sept 2012, 1:57:3926/9/12
a tdde...@googlegroups.com
Muchas gracias por vuestras respuestas!

Además, los dos me habéis dado dos enfoques distintos sobre las ideas que planteaba de los tests, genial!!

Creo que también muchas veces el querer aplicar todos los principios y patrones puede dar sensación de sobre-ingeniería, por ejemplo, aplicar a la vez SOLID y GRASP, que quizás mereciese otro debate...

Ángel, en efecto, fue un lapsus, quería decir cobertura de código, aunque como bien dices, tampoco tiene nada que ver, ya que puedo seguir teniendo cobertura máxima de esa manera. Me refería, como comentas, a que un test llame directamente al método de una clase, que llame a un único componente :)

Lo dicho, muchas gracias,
Diego
Responder a todos
Responder al autor
Reenviar
0 mensajes nuevos