¿Deben los nombres de interfaz comenzar con un prefijo "I"?

73

Con suerte, he estado leyendo " Clean Code " de Robert Martin para convertirme en un mejor programador. Si bien nada de esto hasta ahora ha sido realmente innovador, me ha hecho pensar de manera diferente sobre la forma en que diseño aplicaciones y escribo código.

Hay una parte del libro con la que no solo no estoy de acuerdo, sino que no tiene sentido para mí, específicamente en lo que respecta a las convenciones de nombres de interfaz. Aquí está el texto, tomado directamente del libro. He resaltado el aspecto de esto que encuentro confuso y quisiera aclaraciones.

Prefiero dejar las interfaces sin adornos. El I anterior, tan común en los tacos heredados de hoy, es una distracción en el mejor de los casos y demasiada información en el peor. No quiero que mis usuarios sepan que les estoy entregando una interfaz .

Tal vez sea porque solo soy un estudiante, o tal vez porque nunca he hecho ninguna programación profesional o en equipo, pero me gustaría que el usuario supiera que es una interfaz. Hay una gran diferencia entre implementar una interfaz y extender una clase.

Entonces, mi pregunta se reduce a: "¿Por qué debemos ocultar el hecho de que alguna parte del código espera una interfaz?"

Editar

En respuesta a una respuesta:

Si su tipo es una interfaz o una clase es su negocio, no el negocio de alguien que usa su código. Por lo tanto, no debe filtrar detalles de su código en este código de terceros.

¿Por qué no debería "filtrar" los detalles de si un tipo dado es una interfaz o una clase de código de terceros? ¿No es importante que el desarrollador externo use mi código para saber si implementarán una interfaz o extenderán una clase? ¿Las diferencias simplemente no son tan importantes como las imagino?

Charles Sprayberry
fuente
3
Estoy de acuerdo con su punto. Hay un punto en el que ocultar demasiada información no es muy útil. Sin embargo, incluso si sigue esta directriz, aún podrá distinguir el tipo utilizando el IDE o un complemento.
NoChance
3
Esta pregunta se conoce esencialmente como la pregunta de "notación húngara", debe encontrar muchos argumentos y la razón por la cual la mayoría de los desarrolladores que no son de MS la abandonaron con esta palabra clave. La notación húngara prevaleció principalmente para las variables, pero es esencialmente la misma para los tipos.
thiton
2
La edición previa del título fue terrible. Esta pregunta no se trata de la notación húngara en general simplemente porque menciona una convención que podría estar asociada a ella. Los méritos relativos de HN son totalmente irrelevantes aquí; La pregunta era específicamente acerca de las interfaces frente a las clases y si las diferencias semánticas son o no lo suficientemente importantes o interesantes para justificar una convención de nomenclatura de casos especiales.
Aaronaught
Re to know whether they will be implementing an interface or extending a class: sí, pero la mayoría de los usuarios de su código lo llamarán, no lo implementarán o lo extenderán, y realmente no les importaría cuál es.
david.pfx
Por lo que vale, prefiero masivamente el prefijo "I". También uso un prefijo "abstracto" en clases abstractas por la misma razón. No hace una diferencia para los consumidores de la clase / interfaz, pero puede hacer una gran diferencia para aquellos que necesitan proporcionar instancias de la misma, y ​​también lo hace mucho más simple para otros desarrolladores que están leyendo su código. Significa que pueden ver de un vistazo a qué se enfrentan, en lugar de tener que consultar el IDE caso por caso para obtener más información. ¡Acabo de comenzar a usar Angular y me resulta realmente molesto que no sigan esta convención!
Dan King

Respuestas:

67

Si te detienes a pensarlo, verás que una interfaz realmente no es semánticamente muy diferente de una clase abstracta:

  • Ambos tienen métodos y / o propiedades (comportamiento);
  • Ninguno de los dos debe tener campos no privados (datos);
  • Ninguno de los dos puede ser instanciado directamente;
  • Derivar de uno significa implementar cualquier método abstracto que tenga, a menos que el tipo derivado también sea abstracto.

De hecho, las distinciones más importantes entre clases e interfaces son:

  • Las interfaces no pueden tener datos privados;
  • Los miembros de la interfaz no pueden tener modificadores de acceso (todos los miembros son "públicos");
  • Una clase puede implementar múltiples interfaces (en lugar de poder heredar generalmente de una sola clase base).

Dado que las únicas distinciones particularmente significativas entre clases e interfaces giran en torno a (a) datos privados y (b) jerarquía de tipos, ninguno de los cuales hace la menor diferencia para una persona que llama, generalmente no es necesario saber si un tipo es una interfaz o una clase. Ciertamente no necesitas la indicación visual .

Sin embargo, hay ciertos casos de esquina a tener en cuenta. En particular, si está usando reflexión, intercepción, proxies / mixins dinámicos, tejido de bytecode, generación de código o cualquier cosa que implique meterse directamente con el sistema de mecanografía o el código del entorno, entonces es muy útil y, a veces, es necesario saberlo de inmediato. Bate si estás tratando con una interfaz o una clase. Claramente, no desea que su código falle misteriosamente porque trató de agregar una clase, en lugar de una interfaz, como un mixin.

Sin embargo, para el código de lógica de negocios típico, común y corriente, las distinciones entre clases abstractas e interfaces no necesitan anunciarse porque nunca entrarán en juego.

Dicho todo esto, tiendo a prefijar mis interfaces C # de Itodos modos porque esa es la convención .NET utilizada y defendida por Microsoft. Y cuando estoy explicando las convenciones de codificación a un nuevo desarrollador, es mucho menos complicado usar las reglas de Microsoft que explicar por qué tenemos nuestras propias reglas "especiales".

Aaronaught
fuente
Gracias por este desglose. +1 para las "distinciones significativas entre clases e interfaces ..."
Charles Sprayberry
24
+1 para "Dicho todo esto, tiendo a prefijar mis interfaces C # con I de todos modos porque esa es la convención .NET utilizada y defendida por Microsoft". Esta es una razón suficiente para mí en C #. Al seguir este estándar común, es más probable que otros programadores .NET identifiquen la interfaz.
Robotsushi
44
Como alguien que escribe tanto Java como C #, la afirmación "Dicho todo esto, tiendo a prefijar mis interfaces C # con I de todos modos porque esa es la convención .NET utilizada y defendida por Microsoft" no puede ser subestimada, es una de las cosas que me ayuda a recordar en qué idioma estoy trabajando,
Aidos
3
Otra diferencia en .NET (pero no en Java) es que muchos lenguajes .NET no permiten que las interfaces contengan métodos estáticos, por lo que piratear Iuna interfaz puede dar un buen nombre para que una clase contenga métodos estáticos asociados con la interfaz (p. Ej. Enumerable<T>.Emptyo Comparer<T>.Default)
supercat
Tengo una inquietud En C ++ si abre un encabezado y ve que class Fooya se extiende class Bar, no es inmediatamente obvio si class Barse está extendiendo o implementando. Así que ahora tiene que ir y mirar en el class Barencabezado para decidir si está bien modificar class Foopara extender class Baz. Además, el prefijo I da una pista visual obvia si la "clase base única" se está violando o no, por lo que obtiene un control de cordura cada vez que abre un encabezado.
jsj
14

En muchos sentidos, la coherencia es más importante que la convención. Mientras sea coherente en sus esquemas de nombres, no será difícil trabajar con ellos. Prefije las interfaces con un yo si lo desea, o simplemente deje el nombre sin adornos, ¡no me importa siempre que elija un estilo y se quede con él!

Jim Nutt
fuente
2
+1 para consistencia> convención. En C # prefijarías con una I y en Java no. Diferentes tareas requieren diferentes convenciones
Bringer128
2
+1, mientras que personalmente preferiría no tener Is en mis interfaces, ser inconsistente con las bibliotecas BCL y de terceros utilizadas en proyectos .Net no es una opción en mi humilde opinión.
jk.
13

El libro está lleno de cosas buenas, pero aún agregaría "I" al nombre de la interfaz.

Imagina que tienes public interface ILoguna implementación predeterminada public class Log.

Ahora, si decides tenerlo public interface Log, de repente tienes que cambiar la clase de Log a public class LogDefaultalgo en esas líneas. Pasaste de tener un personaje extra a siete, seguramente eso es un desperdicio.

A menudo hay una delgada línea entre la teoría y la práctica. En teoría esta es una muy buena idea, pero en la práctica no es tan buena.

CodeART
fuente
Esto también se menciona en la documentación de
levininja el
30
"Imagine que tiene una interfaz pública ILog con un registro de clase pública de implementación predeterminada". - Entonces tiene un nombre pobre para su implementación predeterminada. ¿Qué Loghacer? ¿Iniciar sesión en la consola? ¿A syslog? ¿Hacia la nada? Esos deberían llamarse ConsoleLog, SyslogLogy NullLog, respectivamente. Logno es un buen nombre para una clase concreta, porque no es un nombre concreto.
Sebastian Redl
77
Personalmente, esta es exactamente la razón por la que odio ver ITheClassName, ¿estás creando una interfaz sin razón alguna, es solo ruido encima de TheClassName? Si su interfaz tiene un propósito, debería ser posible darle un nombre mejor que ITheClassName
Richard Tingle
El nombre de la clase se usa una vez (para crear instancias), el nombre de la interfaz se usa en todas partes. Agregar una letra a la interfaz para guardar una letra en el nombre de la clase es una economía falsa (de caracteres).
sergut
@RichardTingle Pero creo que el uso común es simplemente que MyClasstiene una variación burlona , ¿verdad? Es decir, a menudo usamos interfaces para hacer que los métodos públicos sean realmente públicos de una manera que permita las pruebas. (No digo que eso es bueno o malo, pero la comprensión de que la motivación para las interfaces es a menudo simplemente para hacer que las clases que son dependencias fácilmente mockable explica la 1-a-1 MyClassa IMyClasslas asignaciones.)
ruffin
8

Bueno, esto no se trata de implementar la interfaz o extender una clase. En estos casos, usted sabe de todos modos lo que está haciendo.

Sin embargo, cuando el código de un tercero (otro módulo de la aplicación, por ejemplo) manipula sus datos, este código no debería importarle si presenta una interfaz o una clase.

Este es todo el punto de abstracción. Está presentando a este código de terceros un objeto de un tipo dado. Este tipo dado tiene alguna función miembro a la que puede llamar. Eso es suficiente.

Si su tipo es una interfaz o una clase es su negocio, no el negocio de alguien que usa su código. Por lo tanto, no debe filtrar detalles de su código a este código de terceros.

Por cierto, las interfaces y las clases son tipos de referencia al final. Y esto es lo que importa. Entonces, esto es lo que su convención de nomenclatura debe enfatizar.

deadalnix
fuente
@ Mat> Sí, fue un error mío y lo edité.
deadalnix
5

La mayoría de las respuestas parecen suponer que el lenguaje de programación es Java o C #, donde hay un concepto (o palabra clave) para interfaces / clases abstractas. En estos casos, en un IDE decente, es inmediatamente visible con qué tipo de clase uno trata y la escritura public interface IMyClasses una duplicación innecesaria. Es como si no escribiera public final FinalMyClass: imagine poner cada palabra clave en el nombre de la clase.

Sin embargo, en mi opinión en C ++, la situación es un poco diferente, ya que uno tiene que sumergirse en el archivo de encabezado y ver si la clase tiene algún método virtual para averiguar si es una clase abstracta. En ese caso, puedo ver claramente un argumento para escribir class AbstractMyClass.

Entonces mi respuesta sería: depende del lenguaje de programación.

Actualizado 2016: 2 años de experiencia en C ++ más adelante Probablemente ahora consideraría una mala práctica prefijar los nombres de clase Abstract, aunque diría que probablemente hay bases de código que son tan complejas que podría tener sentido.

Ela782
fuente
¿Estás seguro de que esto responde la pregunta? Es posible que desee leer las otras respuestas y aclarar algunos de sus puntos.
david.pfx
C ++ definitivamente tiene interfaces, incluso si no hay una palabra clave para ello. ¿Cómo se llama una clase donde cada función miembro es puramente virtual y no hay variables miembro?
@ david.pfx: Creo que respondo con precisión la pregunta "¿Deben los nombres de interfaz comenzar con un prefijo" I "?": Depende del lenguaje de programación. Si cree que mi elaboración no es lo suficientemente clara, me complace mejorarla. ¿Qué partes no le resultan claras?
Ela782
2
@JohnGaughan: ¡Claro que tiene interfaces! Pero mi punto es que se trata de la palabra clave. C ++ no tiene uno, por lo que no es visible para el IDE / usuario si trata con una interfaz o no. En Java, sin embargo, es inmediatamente visible.
Ela782
1
Lea la respuesta de mayor calificación y compare la suya. Usted es nuevo en SO, y esta es una oportunidad para aprender qué tipo de respuestas atraen votos. Tal como está, el tuyo no. Con más trabajo, más explicación, más valor, podría ser. ¡Cuelga ahí!
david.pfx
4

Sigue los modismos del idioma que estás utilizando.

Cada idioma tiene sus propios modismos y pautas de codificación. Por ejemplo, en C #, es idiomático prefijar interfaces con I. En Go, no lo es.

Pete
fuente
+1 Sigue los modismos del idioma que estás utilizando. Obviamente, el autor del libro es un desarrollador de Java. .NET / C #: ILog Java: Log Pero la desventaja: cuando me gusta tener una clase Log que implemente la interfaz ILog ... MyLog, LogDefault, LogBase, ...? Feo, ¿no es así? Más feo es: LogImpl ....: D
hfrmobile
0

En mi código (Java), tiendo a tener esta convención en las API que expongo a las personas que llaman:

  • La funcionalidad se proporciona a través de interfaces, y nunca por clases.
  • Las partes no funcionales son clases.

Por no funcional, me refiero a cosas como estructuras de datos puros (como clases que actúan como puentes para la serialización XML o el ORM), enumeraciones y excepciones, todas las cuales no pueden ser interfaces (bueno, puede hacerlo para las clases de datos puros , pero es mucho trabajo para muy poca ganancia ya que no hay nada que hagan esas clases excepto mantener datos).

En términos de convenciones de nomenclatura, las interfaces tienden a correlacionarse con nombres de actores (por ejemplo, FooBarWatcher) o adjetivos (por ejemplo, FooBarWatchable) y tanto las clases de datos puros como las enumeraciones se asignan a nombres no activos (por ejemplo, FooBarStatus); El IDE puede guiar al consumidor de API sin convenciones de nomenclatura especiales. Excepciones siguen las convenciones habituales (Java FooBarException, FooBarError, FooBarFault), por supuesto.

A menudo también pongo las interfaces en su propio paquete o incluso en su propia biblioteca, solo para asegurarme de que no tengo la tentación de romper mis propias reglas. (Esto también me ayuda a administrar la compilación cuando obtengo el código de fuentes externas como documentos WSDL).

Compañeros de Donal
fuente
Tampoco pongo Iprefijos en las interfaces. ¡Por supuesto que es una interfaz! ¡Está en una API (o SPI)!
Donal Fellows