¿Hay algún inconveniente real en el encadenamiento de métodos autorreferenciales?

14

Hace poco sugerí que se implementara un método de encadenamiento para una clase determinada en un proyecto determinado para que se pudiera mejorar la legibilidad del código. Obtuve una respuesta de "las interfaces fluidas no deberían implementarse solo por conveniencia, sino por semántica" y mi sugerencia fue rechazada. Respondí que no estaba sugiriendo una interfaz fluida sino un método de encadenamiento (ambos pueden confundirse entre sí, leer en la parte inferior) para mejorar la legibilidad y la comodidad de codificación, la sugerencia fue rechazada nuevamente.

De todos modos, esto me hizo pensar que tal vez podría incurrir en una mala práctica al devolver siempre "esto" en métodos que no se supone que devuelvan nada (p. Ej. Setters).

Mi pregunta es: ¿la aplicación de la convención anterior puede considerarse una mala práctica o abuso ?, ¿por qué ?. No creo que haya inconvenientes en el rendimiento, ¿o sí?

dukeofgaming
fuente
2
Mire esta pregunta para una buena discusión programmers.stackexchange.com/questions/48419/…
KeesDijk
@KeesDijk Gracias, edité mi pregunta un poco para que no sea similar a esa, ya que estoy más interesado en el caso de los métodos de encadenamiento de la misma clase
dukeofgaming
1
en SO, me dijeron, que el encadenamiento no es para C ++ - stackoverflow.com/questions/5760551/… - ¿en qué piensas?
kagali-san
1
@mhambra Parece que solo necesitaría tener cuidado al implementar el encadenamiento de métodos y definir estándares claros para eso.
dukeofgaming

Respuestas:

10

No

Como señala Kent Beck , el código se lee con mucha más frecuencia de lo que se escribe.

Si el encadenamiento de métodos hace que su código sea más legible, entonces use el encadenamiento de métodos.

Steven A. Lowe
fuente
1
Gran libro .. +1
Rein Henrichs
55
PERO , ¿qué pasa si usted es el único método de búsqueda que encadena más legible? Si se trata de un problema de síntesis, entonces deberá apegarse a un conjunto de convenciones de codificación: esto significa, escribir de la misma manera que el código existente, para mantener la coherencia.
coredump
@coredump Parece que ya se le ha dicho al OP que haga eso, pero creo que Steven solo estaba diciendo esto porque si el encadenamiento del método lo hace más legible.
Panzercrisis
1
A @Panzercrisis OP se le ha dicho que se abstenga de usar el método de encadenamiento debido a la conveniencia frente a la semántica. La respuesta de Steven básicamente dice "hazlo de todos modos" y solo considera la legibilidad del código de OP por sí mismo, sin considerar la opinión o consistencia del equipo. ¿Qué sucede si OP desea reescribir cada clase existente en el proyecto para que se adapte a su gusto con respecto a la legibilidad del código? Así es como entiendo el argumento de conveniencia / semántica: debería haber una razón "técnica" para tener un método de encadenamiento (por cierto, ese argumento también parece que la otra persona está inventando una excusa para sus propias preferencias)
coredump
9

Si, hay inconvenientes

El código que es fácil de leer es bueno, pero también tenga cuidado con lo que el código comunica . Cuando los métodos de un objeto siempre devuelven el objeto, comunica un par de cosas:

  1. Necesito una configuración avanzada que no sea necesariamente obvia en qué orden se deben configurar o configurar las cosas
  2. Cada llamada de método posterior se basa en el último

Caso de uso válido: consultas de base de datos ad hoc

Las bibliotecas de clases existen en la mayoría de los idiomas que le permiten consultar una base de datos sin recurrir a SQL codificado. Tome el Entity Framework para .NET como ejemplo:

DBContext db = new DBContext();
List<Post> posts = db.Posts
    .Where(post => post.Title.Contains("Test"))
    .OrderBy(post => post.DateCreated)
    .ToList();

Esta es una interfaz fluida donde cada llamada de método posterior se basa en la anterior. Leer estas llamadas lógicamente tiene sentido en el contexto de consultar una base de datos.

Caso de uso no válido: azúcar sintáctico para establecer propiedades

Ahora usemos el mismo patrón con la Postclase:

public class Post
{
    public string Title { get; set; }
    public DateTime DateCreated { get; set; }
    public string Body { get; set; }

    public Post SetTitle(string title)
    {
        Title = title;

        return this;
    }

    public Post SetDateCreated(DateTime created)
    {
        DateCreated = created;

        return this;
    }

    public Post SetBody(string body)
    {
        Body = body;

        return this;
    }
}

Ahora veamos cómo usarías esta clase:

Post post = new Post()
    .SetTitle("Test")
    .SetDateCreated(DateTime.Now)
    .SetBody("Just a test");

Cuando veo este código, inmediatamente hago esta pregunta: "Después de llamar SetBody , ¿consulta la base de datos? ¿Necesito llamar a otro método para decir 'Ya terminé?'"

¿Qué comunican las llamadas al método encadenado al código usando la Postclase?

  1. Tengo una configuración complicada
  2. Cada llamada al método se basa en la anterior

¿Es esto realmente cierto? No. La Postclase no tiene una configuración complicada. Establecer el título, la fecha de creación y el cuerpo no complementan entre sí hacia un objetivo final más complicado. Has machacado una clavija cuadrada en un agujero redondo.

El inconveniente del encadenamiento de métodos autorreferencial es que usted comunica que se requieren múltiples llamadas a métodos para hacer algo, y que cada llamada se basa en la última. Si esto no es cierto, entonces el encadenamiento de métodos podría estar comunicando lo incorrecto a otros programadores.

Cuando tus compañeros de trabajo dijeron:

Las interfaces fluidas no deben implementarse solo por conveniencia, sino también por semántica

Eran absolutamente correctos. Una interfaz fluida, o encadenamiento de métodos, comunica algo en sí mismo que podría no ser cierto.

Greg Burghardt
fuente
Esto supone que el encadenamiento de métodos y la configuración compleja siempre van de la mano. Son entidades distintas y la presencia de una no debería hacerte asumir la otra.
Jack
No se trata solo de "configuración compleja", sino también de "llamadas a métodos posteriores a partir de la anterior". El encadenamiento de métodos tiene una metacomunicación al respecto que no siempre es fiel al propósito de una clase.
Greg Burghardt
1
Las llamadas de métodos posteriores que se basan en las anteriores también son distintas del encadenamiento de métodos, y no creo que tratar la sintaxis del encadenamiento de métodos como una comunicación fuerte para la semántica de las series de operaciones de efectos secundarios dependientes del orden sea confiable o útil. Es una taquigrafía sintáctica, nada más. Úselo donde hace las cosas más cortas y más legibles.
Jack
1
Tengo entendido que piensa método de encadenamiento es independiente, sino que estoy diciendo que otros programadores que no estaban dentro de su cabeza y utilizan otras bibliotecas de clases que no implementan método de encadenamiento de estas razones podría llegar a hacer suposiciones acerca de su código que no son ciertas. Tenga en cuenta que el método de encadenamiento podría implicar algo que usted, el autor del código, no pretendía. El código que se comunica claramente es tan importante como el código que es fácil de leer. No sacrifiquen uno por el otro.
Greg Burghardt
1
When an object's methods always return the object, it communicates a couple of things- Creo que esta es una opinión personal; Es difícil afirmar que todos los que busquen métodos encadenados asumirán las mismas cosas.
Sam Dufel
1

El principal inconveniente es la pérdida de claridad. Por ejemplo:

x.foo();
x.bar();
x.baz();

Como ninguna de esas declaraciones devuelve un valor (o si lo hacen, se ha ignorado), solo pueden ser útiles si producen efectos secundarios. Contraste eso a:

x.foo()
 .bar()
 .baz();

Primero, no está claro eso bary bazopera en objetos del mismo tipo que x, a menos que sepa de hecho que esa xclase es la única clase con esos métodos. Incluso si ese es el caso, no está claro si funcionan los métodos xo los objetos nuevos.

Resaltar las partes del código que tienen efectos secundarios es útil, ya que necesita rastrear esos efectos secundarios para razonar sobre el programa. Debe sopesar la posible pérdida de claridad frente a la ganancia potencial en la facilidad de escribir código, pero también considere que el código se lee más de lo que se escribe.

Doval
fuente
0

Considere todos los elementos estilísticos de los lenguajes de programación (a diferencia del lenguaje de máquina de codificación manual), y debilita el argumento de "semántica no conveniencia".

Mucho de lo que hacemos como ingenieros es proporcionar comodidad en torno a la semántica.

Robar
fuente