2010-06-09 12 views
10

en todos los artículos (ágiles) que he leído sobre esto: mantenga su código y funciones pequeños y fáciles de probar.Cómo mantener mis funciones (objetos/métodos) 'pobre y malo'

¿Cómo debo hacer esto con la clase 'controlador' o 'coordinador'?

En mi situación, tengo que importar datos. Al final tengo un objeto que coordina esto, y me preguntaba si hay una manera de mantener al coordinador delgado (er) y malo (er).

Mi coordinador hace ahora la followling (pseudocódigo)

//Write to the log that the import has started 
Log.StartImport() 
//Get the data in Excel sheet format 
result = new Downloader().GetExcelFile() 
//Log this step 
Log.LogStep(result) 
//convert the data to intern objects 
result = new Converter().Convertdata(result); 
//Log this step 
Log.LogStep(result) 
//write the data 
result = Repository.SaveData(result); 
//Log this step 
Log.LogStep(result) 

En mi humilde opinión, este es uno de los '' conocer todas las clases o por lo menos uno de ellos 'no clara y directa'? O, ¿estoy llevando esto delicado y malo hasta el momento y es imposible programar una importación sin algún tipo de importador/coordinador "gordo"?

Michel

EDITAR esto es realmente un dos-en-uno pregunta: uno es la forma de probar que, en segundo lugar es si está bien tener un 'saber todo/pegamento todos juntos' coordinador

+0

Su pseudocódigo puede ser más claro si nombra mejor la variable "resultado". Supongo que no debe ser lo mismo cada vez. –

Respuesta

11

Estoy seguro de que muchas personas estarían en desacuerdo, pero creo que su método es en general lo suficientemente pobre. El bit crucial que te falta aquí es la inyección de dependencia (también conocida como inversión de control), así que en lugar de actualizar Downloader, Converter, etc. dentro de tu método, debes definir interfaces para estas clases e "inyectarlas" en el constructor de tu clase:

private Downloader downloader; 
private Converter converter; 

public MyClass(Downloader downloader, Converter converter) 
{ 
    this.downloader = downloader; 
    this.converter = converter; 
    //same with repository, it can't be a static class anymore 
} 

entonces sólo tiene que utilizar estos casos en su método:

//Write to the log that the import has started 
Log.StartImport() 
//Get the data in Excel sheet format 
result = downloader.GetExcelFile() 
//Log this step 
Log.LogStep(result) 
//convert the data to intern objects 
result = converter.Convertdata(result); 
//Log this step 
Log.LogStep(result) 
//write the data 
result = repository.SaveData(result); 
//Log this step 
Log.LogStep(result) 

ahora después de hacer este cambio, en la prueba que se puede utilizar uno de los marcos burlones (utilizo RhinoMocks) para inyectar una implementación burlada de las dependencias en su clase. De esta forma, puede verificar que se haya invocado el método correcto en el convertidor y el descargador, sin leer nada del disco ni analizar ninguna hoja de cálculo.

ejemplos de cómo utilizar RhinoMocks están en su documentación: http://ayende.com/wiki/Rhino+Mocks+Documentation.ashx

No dude en hacer otra pregunta si te quedas atascado :)

+0

Gracias por su respuesta. He leído mucho sobre burlas, pero nunca me atreví a usarlo. Si utilizo un simulacro, todavía tengo que probar el lector de Excel "real" ¿no? En algún momento tengo que probar si el programa de descarga realmente es una hoja de Excel de algún Uri, ¿no? ¿O esa prueba ya no se llama prueba unitaria sino más bien una prueba de integración? – Michel

+0

Crearía una interfaz para Log también. El registro es una dependencia oculta que no se puede burlar como lo es ahora. –

+0

Bien, siempre estoy atrapado en la dependencia de registro – Michel

3

Tuve un problema similar y la manera en que lo resolví fue realmente tener una visión adecuada del SRP (Principal de Responsabilidad Individual).

ExcelFileReader que puede leer el archivo de Excel y devolver un conjunto de lista (líneas)

Analizador Es el trabajo es analizar las líneas volvieron de la ExcelFileReader con el delimitador

Importador que maneja la importación del DataSet devuelto desde FileParser a las tablas correctas.

Esto lo mantiene en forma comprobable ya que ExcelFileReader no depende del Analizador o Importador. Esto va para el Analizador, así como también se puede probar con solo pasarle un Lector de Texto.

¿Le sirve de ayuda?

+0

el problema es que una de sus clases es la responsabilidad de mediar con otras clases. En teoría, es fácil agregar muchas responsabilidades en un solo resumen, pero en la práctica no siempre es tan fácil o el desarrollador es amigable con el tiempo. –

+0

Creo que eso es lo que hizo. – Grzenio

+0

Esto es más o menos lo que he hecho hasta ahora, he creado clases para cada paso principal (lea Excel, convierta y guarde). Entonces, sin conocer SRP, lo he usado :-). Pero lo que resta es que tengo un coordinador que toma la hoja de Excel del importador, la entrega al convertidor, recupera los datos convertidos y los entrega al repositorio. En el medio también se guarda todo tipo de datos en los logtables, por lo que el método del coordinador ('StartImport') es un método 'gordo'. – Michel

1

Es muy común tener una clase que hace lo que creo que es el mediator pattern.

Una forma que he encontrado para combatir las clases que tienen que tener colaboradores (que es con lo que te estás metiendo en este momento) es hacer Prueba de Unidad Simulada.

Básicamente se burla de sus colaboradores y establece expectativas para esos colaboradores.

Lamentablemente está utilizando C# y no conozco ninguna biblioteca de Mock para C#. Sin embargo, estoy seguro de que Google puede ayudarlo a encontrar una biblioteca falsa.

En lugar de una biblioteca de simulación, puede implementar o ampliar las clases de su colaborador y anular e implementar los métodos que espera llamar con métodos que producen el resultado esperado.

Según lo observado por Michael, es mucho más fácil si tiene cableado de inyección de dependencia en sus colaboradores.

+0

El patrón del mediador parece prometedor – Michel

0

yo encontramos este article particularmente útil al momento de decidir si era mi código de hecho clara y directa

1

Sus comentarios y registrador (? Singleton) son demasiado ruidoso:

Log.StartImport(); 
result = new Downloader().GetExcelFile() 
Log.Step(result); 
result = new Converter().Convertdata(result); 
Log.Step(result); 
result = Repository.SaveData(result); 
Log.Step(result); 

Y dado que tiene tres pasos que tienen que suceder juntos, envuélvalos en Converter. Usando DI pase a Converter a Downloader y Repository. Ahora termina con:

Log.StartConvert(); 
convert.ExcelToRepository(); //passed in with DI 

Nota todos los resultados del paso de registro se realizan en sus respectivas acciones.

+0

Buen punto de vista. Me preguntaba si podría poner el registro en las acciones respectivas porque pensé que tal vez el convertidor de Excel no debería saber nada sobre el registro porque no es su preocupación sino más la preocupación del convertidor. – Michel

+0

El inicio de sesión es una preocupación transversal para empezar. Si le preocupan estas cuestiones transversales, puede recurrir a un sistema de mensajería que tenga múltiples suscriptores en un único editor de eventos. De lo contrario, presione el registro lo más cerca posible de la acción. Recuerde, ** ¡dígale, no pregunte! **. Sigue la * Ley de Demeter *. – Gutzofter

Cuestiones relacionadas