unit tools test how ejemplo unit-testing interface dependency-injection tdd coding-style

unit testing - tools - Prefijando interfaces con I?



unit testing php (3)

Actualmente estoy leyendo "Clean Code" por Rober Martin (UncleBob), y en general me encantan las reflexiones de UncleBob. Sin embargo, me confundí un poco, cuando leí que evita las interfaces de prefijo como "IPerson". Afirma que "no quiero que mis usuarios sepan que les estoy entregando una interfaz".

Pensando desde la perspectiva de la TDD / inyección, siempre estaré muy interesado en decirle a los "usuarios" de mis clases que estoy entregando una interfaz. La razón principal es que considero que los contratos de Interfaces entre los diferentes "agentes" de un sistema. Un agente que trabaja con una esquina de mi sistema, no debe saber la implementación concreta de otro trabajo de agentes; solo deben intercambiar contratos, y esperar que los contratos se cumplan sin saber cómo. La otra razón, pero también muy importante, es que una interfaz se puede simular completamente y, por lo tanto, hace que la prueba de unidades sea mucho más fácil. Hay límites a cuánto puedes burlarte de una clase concreta.

Por lo tanto, prefiero visualizar que efectivamente estoy transmitiendo una interfaz ... o tomando una interfaz como argumento. Pero dado que UncleBob es un campeón de peso pesado en nuestra comunidad, y soy solo otro jockey de escritorio, me gustaría saber si me estoy perdiendo algo.

¿Es incorrecto para mí insistir en que estoy en interfaces?


Considero los contratos de Interfaces entre los diferentes "agentes" de un sistema. Un agente que trabaja con una esquina de mi sistema, no debe saber la implementación concreta de otro trabajo de agentes; solo deben intercambiar contratos, y esperar que los contratos se cumplan sin saber cómo. La otra razón, pero también muy importante, es que una interfaz se puede simular completamente y, por lo tanto, hace que la prueba de unidades sea mucho más fácil. Hay límites a cuánto puedes burlarte de una clase concreta.

Todo esto es cierto, pero ¿cómo se necesita una convención de nomenclatura para las interfaces?

Básicamente, el prefijo de interfaces con "I" no es más que otro ejemplo del tipo inútil de notación húngara, porque en un lenguaje tipificado estáticamente (el único tipo en el que las interfaces como construcción de lenguaje tienen sentido) siempre puede encontrar fácil y rápidamente qué El tipo es, usualmente moviendo el mouse sobre él en el IDE.


Hay una serie de convenciones en Java y C # con las que nos hemos sentido cómodos; Pero eso es al revés. Por ejemplo, la convención de poner las variables privadas en la parte superior de cada clase es bastante tonta desde un punto de vista técnico. Las cosas más importantes acerca de una clase son sus métodos públicos. Las cosas menos importantes, las cosas que escondemos detrás de una barrera de privacidad, son las variables de instancia. Entonces, ¿por qué los ponemos en la parte superior?

La "I" frente a las interfaces es otra convención hacia atrás. Cuando se le pasa una referencia a un objeto, debe esperar que sea una interfaz. Las interfaces deben ser las predeterminadas; así que no tiene sentido hacer algo extra, como usar un prefijo I, para anunciar que está haciendo lo que todos esperan que haga. Sería mejor (aunque sea incorrecto) si reserváramos un marcador especial para la condición excepcional de aprobar una clase concreta.

Otro problema con el uso de I, es que (de manera extraña) lo usamos para comunicar la decisión de implementación de usar una interfaz. Por lo general, no queremos que las decisiones de implementación se expresen tan fuerte, porque eso las hace difíciles de cambiar. Considere, por ejemplo, qué podría pasar si decide que IFoo realmente debería ser una clase abstracta en lugar de una interfaz. ¿Debes cambiar el nombre a Foo o CFoo, o ACFoo?

Puedo escuchar las ruedas girando en tu cabeza. Está pensando: "Sí, pero las interfaces tienen un lugar especial en el idioma, por lo que es razonable marcarlas con una convención de nombres especial". Es verdad. Pero los enteros también tienen un lugar especial en el idioma, y ​​ya no los marcamos (más). Además, pregúntate esto, ¿por qué las interfaces tienen un lugar especial en el idioma?

Toda la idea detrás de las interfaces en Java y C # fue una anulación. Los diseñadores de lenguaje podrían haber usado clases abstractas, pero estaban preocupados por las dificultades de implementar la herencia múltiple. Así que hicieron un trato de trastienda con ellos mismos. Inventaron una construcción artificial (es decir, interfaces) que proporcionaría parte del poder de la herencia múltiple, y restringieron las clases normales a una herencia única.

Esta fue una de las peores decisiones que tomaron los diseñadores de idiomas. Inventaron un elemento de sintaxis nuevo y pesado para excluir una característica de lenguaje útil y poderosa (aunque controvertida). Las interfaces no se inventaron para habilitar, se inventaron para inhabilitar . Las interfaces son un truco colocado en el lenguaje por diseñadores que no querían resolver el problema más difícil de MI. Entonces, cuando usas el prefijo I, estás poniendo un gran foco en uno de los hacks más grandes en la historia del idioma.

La próxima vez que escriba una firma de función como esta:

public void myFunction(IFoo foo) {...}

Pregúntate esto: "¿Por qué quiero saber que el autor de IFoo usó la palabra ''interfaz''? ¿Qué diferencia me hace saber si usó ''interfaz'' o ''clase'' o incluso ''struct''? Ese es su negocio, "¡No es mío! ¿Entonces por qué me obliga a conocer su negocio al poner a este gran I delante de su nombre tipográfico? ¿Por qué no comprime sus declaraciones y mantiene sus secretos al margen?"


Si estás hablando de .NET, entonces las interfaces con I al principio son tan omnipresentes que eliminarlas confundiría a todos.

Además prefiero tener

public class Foo : IFoo {}

que

public class FooImpl : Foo {}

Todo se reduce a las preferencias personales y lo hice durante un tiempo jugando con la idea, pero volví al prefijo I YMMV