¿Cómo evitar nombres generales para clases abstractas?

10

En general, es bueno evitar palabras como "manejar" o "procesar" como parte de los nombres de rutina y nombres de clase, a menos que se trate de (por ejemplo) identificadores de archivos o (por ejemplo) procesos unix. Sin embargo, las clases abstractas a menudo no saben qué van a hacer con algo además de, por ejemplo, procesarlo. En mi situación actual, tengo un "EmailProcessor" que inicia sesión en la bandeja de entrada de un usuario y procesa los mensajes de esta. No tengo muy claro cómo darle un nombre más preciso, aunque he notado que surge la siguiente cuestión de estilo:

  • ¿Es mejor tratar las clases derivadas como clientes y nombrar la clase base por la parte de la funcionalidad que implementa? Le da más significado pero violará is-a. Por ejemplo, EmailAcquirer sería un nombre razonable ya que está adquiriendo para la clase derivada, pero la clase derivada no lo estará para nadie.
  • O simplemente un nombre realmente vago, ya que quién sabe lo que harán las clases derivadas. Sin embargo, "Procesador" sigue siendo demasiado general ya que está realizando muchas operaciones relevantes, como iniciar sesión y usar IMAP.

¿Alguna salida a este dilema?

El problema es más evidente para los métodos abstractos, en los que realmente no puede responder la pregunta "¿qué hace esto?" porque la respuesta es simplemente "lo que el cliente quiera".

djechlin
fuente
¿Tiene una fuente (y algún contexto) para esa afirmación "en general"? Además, una regla de nomenclatura adicional para la lista: no pierda el tiempo buscando un nombre perfecto que probablemente no exista. En caso de duda, dele el mejor nombre posible, agregue una descripción más larga como un comentario donde se define si es necesario, pero siempre puede refactorizar más tarde si a alguien no le gusta su elección o el nombre perfecto se le ocurre de repente cuando usted ' Estás haciendo otra cosa.
Steve314
3
@ Steve314: sí, Steve McConnell, Code Complete, 1st ed., Capítulo 4 o 5 sobre rutinas. Discusión extensa sobre los nombres en estos capítulos, esencialmente concluyendo que si no tiene un buen nombre, probablemente no tenga una buena función.
djechlin
no encontrar un buen nombre puede parecer una mala señal, pero en mi opinión, debes saber si la función es mala en función de la función misma. Refactorizar solo porque el idioma inglés no fue diseñado a medida para su proyecto es un poco tonto. No, no es un problema cotidiano, pero ya decidió que tenía un problema.
Steve314
1
@ Steve314 La programación se trata por completo de gestionar la complejidad, y si su cerebro no puede encontrar una palabra para algo, hay muchas posibilidades de que no pueda gestionar su complejidad cuando tiene que hacer cosas como usarlo en oraciones más grandes o como parte de sistemas más grandes. En realidad, no es una afirmación audaz decir que la incapacidad para encontrar un buen nombre es una gran causa para preocuparse. Pero esto se discute ampliamente en McConnell, recomendaría leer esos dos capítulos al menos, aunque vale la pena leer todo el libro de principio a fin.
djechlin
los reclamos en Code Complete no necesariamente deben ser confiables. Soy consciente de la reputación de los libros, pero también soy consciente de esto . Además, he manejado la complejidad perfectamente bien durante años: los errores ocurren, por supuesto, pero cuando las cosas van mal, a veces el problema es una función tan simple que obviamente no puede estar equivocada, pero lo es de todos modos .
Steve314

Respuestas:

10

El problema no es el nombre, sino que estás poniendo demasiado en una clase.

En su clase de ejemplo, algunas partes son muy concretas (cómo se obtendrán los correos). Otras partes son muy abstractas (lo que harás con los correos).

Es mejor hacer esto con clases separadas, que con la herencia.

Yo sugiero:

  • un MessageIterator abstracto, subclasificado por un POPMailBoxDownloader

  • otra clase que posee un POPMailBoxDownloader y hace algo con los mensajes.

Kris Van Bael
fuente
Esto suena exactamente bien. Parece que si te encuentras nombrando algo "processEvent" o una clase "MessageProcessor", hay muchas posibilidades de que hayas diseñado sobre la composición en lugar de la derivación. En este caso es una compensación, ya que los mantenedores la flexibilidad puede ser útil, pero un cliente se molestaría al preguntarse exactamente qué hace cada función (más que el mantenedor).
djechlin
6

Si no puedo encontrar un buen nombre para una clase, escribo una documentación de código en línea para la clase. Describe el propósito de la clase en una esencia. Por lo general, puedo derivar un buen nombre para la clase de esta descripción. Esto también es útil para las clases abstractas.

Si la descripción de la clase es "Inicia sesión en la bandeja de entrada de un usuario y procesa mensajes de ella", sugeriría "InboxProcessor" como nombre de clase. Si una clase derivada tiene "Inicia sesión en la bandeja de entrada de un usuario y mueve el correo electrónico no deseado a una carpeta de correo no deseado" como descripción, elegiría "InboxSpamMover" como nombre.

No veo un problema cuando uso nombres genéricos como "procesador" si refleja el propósito genérico de una clase abstracta.

Si tiene problemas para describir el propósito de una clase en una o dos escenas, puede que tenga un problema de diseño. Tal vez la clase está haciendo demasiado y viola el Principio de responsabilidad única . Esto también se aplica a las clases abstractas.

Theo Lenndorff
fuente
2

Parafraseando a Frank Zappa, es lo que es y debe llamarse así. Su ejemplo simplemente no profundiza lo suficiente en qué tipo de procesamiento está ocurriendo. ¿Es un EmailToTroubleTicketProcessor, un EmailGrammarCorrectoro un EmailSpamDetector?

El problema es más evidente para los métodos abstractos, en los que realmente no puede responder la pregunta "¿qué hace esto?" porque la respuesta es simplemente "lo que el cliente quiera".

Eso no es exactamente cierto; la pregunta que no puede responder para algo abstracto es " ¿cómo hace lo que hace?" porque eso es específico de implementación. Si una EmailSenderclase tiene un DeliveryStatus deliver(Email e)método, hay un contrato implícito de que una implementación tomará un correo electrónico, tratará de entregarlo y devolverá algún estado sobre cómo fue. No le importa si se conecta a un servidor SMTP o si lo imprime para amarrarlo a una paloma mensajera, siempre que la implementación cumpla lo prometido. Los resúmenes simplemente cuantifican esa promesa para que una implementación pueda decir, "sí, hago eso".

Blrfl
fuente
¿Qué pasa cuando la función final es en cierto sentido terminal, por lo que la clase abstracta dice "y esto aquí, haga lo que quiera con ella?" por ejemplo, el método no tiene acceso al estado, tipo de retorno nulo, no-throw.
djechlin
Sigue siendo lo mismo. Incluso si su método es void doWhatYouDoWith(Email e), aún podría llamar a la clase un EmailDisposer, que es lo suficientemente específico como para decir lo que hace, pero lo suficientemente general como que depende de la implementación. Aunque creo que @KrisVanBael lo logró: si ha recurrido a algo tan ambiguo, puede haber demasiado bajo un mismo techo.
Blrfl
0

Piensa por qué es malo usar esas palabras. ¿Son descriptivos? ¿Qué palabras hay para describir las clases? EmailBaseClass? ¿Podría ser más descriptivo que decir EmailManager o algo similar? La clave es tener una idea de la clase en cuestión, así que encuentra los verbos o sustantivos adecuados. Trata tu código como si fuera poesía.

zxcdw
fuente
"EmailBaseClass" sería como nombrar int age"ageInteger", incluso peor, ya que esperaría obtener correos electrónicos de texto sin formato, correos electrónicos MIME, etc. No es necesario describir lo que está precedido por la palabra abstracten primer lugar (esto es Java). ¿Tiene alguna idea particular para la parte base de esta clase? Y una mayor comprensión aún no resuelve el problema de nombrar algo que va a estar cruzando una relación is-a, puedo tener algo demasiado vago o demasiado general, no veo una salida de esto a menos que haya tenido más perspicacia para tener más perspicacia.
djechlin
@djechlin: hay casos raros en los que ageIntegero algo así es realmente apropiado. La notación húngara es una versión abreviada de un contexto en el que sucedió mucho. Ciertamente, hay momentos en los que puede necesitar algo en la misma línea ageNumericy ageStringen el mismo ámbito, con una indicación del tipo en el nombre que es la forma más fácil y clara de desambiguar.
Steve314
@djechlin Personalmente me parece más fácil trabajar con el código que acaba puedo mirar a obtener una comprensión. Es decir, los nombres me dicen con qué estoy trabajando. No es necesario saber si systemControlleres una clase base abstracta o una hoja en una gran jerarquía. Por supuesto, esto puede remediarse con IDE (como supongo que es el caso con la mayoría del desarrollo de Java), que puede informar inmediatamente al usuario sobre el contenido y la estructura de la clase, por lo que los nombres perspicaces no pueden justificarse de manera similar.
zxcdw