¿Mantener mis clases y métodos lo más pequeños posible?

20

Hace unos días, estaba hablando con un candidato a doctorado en Ingeniería de Software y en algún momento me dijo:

Mantenga sus clases y métodos lo más pequeños posible

Y me pregunto si esto siempre es una buena práctica.

Quiero decir, por ejemplo, ¿es digno de tener una clase con solo 2 atributos? Por ejemplo, en algunos métodos necesito pares de enteros para trabajar. ¿Debo escribir una clase "PairOfIntgers"?

¿Podría esta forma de pensar "romper" el código en demasiadas piezas?

Florents Tselai
fuente
10
Eso debería ser"As small as possible, but no smaller."
StuperUser
"Quiero decir, por ejemplo, ¿vale la pena tener una clase con solo 2 atributos?" - Puede ser, busque "Primitive Obsession" (por ejemplo, jamesshore.com/Blog/PrimitiveObsession.html )
Torsten
Creo que la fuente de confusión es la palabra "posible". El principio se vuelve ridículo si "posible" se refiere solo al código, porque la clase más pequeña posible que hace algo útil tiene solo un método (y en algunos casos cero). Es muy probable que el candidato tenga en cuenta la cohesión y el acoplamiento.
Kelvin

Respuestas:

23

Hay un grano de verdad en ese consejo, pero en mi humilde opinión, no está muy bien expresado, por lo que es fácil de malinterpretar y / o llevar a un extremo estúpido. En cualquier caso, esto debería ser una regla general, más que una ley estricta. Y siempre debe implicar en tales reglas la cláusula "dentro de límites razonables" o "pero no olvide usar su sentido común" :-)

El grano de la verdad es que, en la práctica, las clases y los métodos siempre tienden a crecer por naturaleza, no a reducirse . Una corrección de errores aquí, una pequeña extensión de funciones allí, manejar un caso especial allí ... y listo, tu clase, una vez ordenada y pequeña, comienza a hincharse. Con el tiempo, su código casi inevitablemente tiende a convertirse en un monstruoso desastre de espagueti, a menos que luche activamente contra esta tendencia mediante la refactorización . La refactorización casi siempre produce muchas clases / métodos más pequeños a partir de unos pocos grandes. Pero, por supuesto, hay un límite razonable para la miniaturización. El objetivo de la refactorización no es tener clases y métodos más pequeños per se, sino hacer que su código sea más limpio, más fácil de entender y mantener. En cierto punto, hacer que sus métodos / clases sean más pequeños comienza a disminuir la legibilidad, en lugar de aumentarla. Apunte hacia ese óptimo. Es un área objetivo borrosa y en movimiento, por lo que no es necesario golpearla. Simplemente mejore un poco el código cada vez que note algún problema con él .

Péter Török
fuente
1
Definitivamente, una regla para no seguir a ciegas, demasiadas clases pequeñas es mucho peor que algunas clases más grandes la mayor parte del tiempo.
Ryathal
44
Mi regla general es: si no puede ver la implementación de un método completo en la pantalla a la vez, refactorice.
Dan Ray
66
@DanRay, sí, solía tener la misma regla, hasta que leí Código limpio . Fue un shock, pero gradualmente causó que mi óptimo bajara a alrededor de 10 líneas.
Péter Török
2
IMO Clean Code es horrible en su extremo hacia los métodos pequeños. El problema es que cuando los métodos se hacen más pequeños, habrá más de ellos. Por supuesto, los métodos demasiado largos son demasiado largos, pero Bob Martin parece preferir 10 métodos de 1 línea sobre 1 de 10 líneas (por lo tanto, el mismo código ocupa aproximadamente 5 veces más espacio en la pantalla). Tal vez sea un truco educativo, no puedo creer que alguien piense que el código de ese libro es bueno.
Joonas Pulakka
55
@JoonasPulakka - Digamos que nunca leí un método y pensé: "Me gustaría que este método hiciera más". Al acortar los métodos, puede escribir nombres de métodos muy descriptivos que a menudo pueden eliminar la necesidad de leer el cuerpo del método por completo. El consejo de Clean Code me pareció muy sensato. Solo tendremos que aceptar estar en desacuerdo. :)
David Harkness
9

El tema más importante para enfatizar aquí es crear buenas abstracciones . Las clases pequeñas que están unidas libremente y tienen una alta cohesión son producto de buenas abstracciones .

A veces tiene mucho sentido encapsular dos enteros en una clase. Especialmente si desea tener métodos 'adjuntos' a esta clase para encapsular también cómo se pueden manipular estos atributos y asegurarse de protegerlos de otras partes del programa que los cambian.

Otro aspecto positivo para crear una clase en este caso es que la clase puede evolucionar mucho mejor / mejor que, digamos, una estructura de datos de nivel inferior como un Mapa o Lista.

Tercero, una buena abstracción puede mejorar mucho la legibilidad. Las clases que se adhieren a SRP suelen ser mucho más fáciles de entender por un humano que las clases que no lo hacen.

Y solo como nota final ... no importa cuán bueno de estudiante seas ... para entender la POO y las buenas abstracciones y cuándo usarlas, necesitas experiencia. Necesita escribir un código incorrecto y pasar por el dolor para mantenerlo. Necesita ver a otros escribir un buen código para desarrollar su conocimiento sobre lo que es 'bueno' y lo que será un problema en el futuro ... Así que no se castigue si simplemente no lo entiende de inmediato.

c_maker
fuente
2

El antipatrón del Objeto de Dios es a lo que probablemente aludía. Tiendo a pensar que si tengo un "y" en la descripción de mi clase, debería tener dos clases. Si tengo más de diez líneas de código en un método / función, entonces debería dividirlo. Como el código pirata, esas son más pautas que reglas.

Sardathrion - Restablece a Monica
fuente
2

En la programación orientada a objetos, el principio de responsabilidad única establece que cada objeto debe tener una responsabilidad única, y esa responsabilidad debe estar completamente encapsulada por la clase. Por lo general, estás haciendo más de una cosa si tu clase es demasiado grande. En su caso, la clase es solo una clase de datos que contiene datos que están totalmente bien. No debe nombrar la clase PairOfInteger. ¿Qué describen los enteros? Dependiendo de su escenario, una Tupla (como en C #) también podría ser suficiente. Y es posible que desee pensar en un puntal en lugar de una clase.

Intenta mantener tus clases pequeñas. Y métodos aún más pequeños. ¿Quizás 10 líneas? Actualmente estoy tratando de usar diseño de flujo y componentes basados ​​en eventos que parecen ayudar a mantener las clases pequeñas. Primero me preocupaba llegar a muchas clases, ¡pero realmente funciona! http://geekswithblogs.net/theArchitectsNapkin/archive/2011/03/19/flow-design-cheat-sheet-ndash-part-i-notation.aspx http://geekswithblogs.net/theArchitectsNapkin/archive/2011/03 /20/flow-design-cheat-sheet-ndash-part-ii-translation.aspx

KCT
fuente
2

Haga las cosas lo más simple posible, pero no más simple. Esa es la regla que trato de seguir. A veces, en realidad tiene sentido que una clase haga lo que estrictamente hablando equivale a más de una cosa, si esas cosas están relacionadas con algún tema común . Mira .NET; Hay toneladas de clases que implementan una gran cantidad de interfaces, cada una con su propia lista de miembros requeridos. Un método podría terminar necesitando ser algo largo si hace algo complejo con una serie de pasos intermedios que están todos interconectados y, por lo tanto, no se prestan muy bien para una refactorización adicional. (La refactorización para mantener los métodos cortos debería ser, en última instancia, acerca de la legibilidad y la mantenibilidad; si el método largo es más legible y / o mantenible que uno corto, todo lo demás igual, tomaré el largo cualquier día).

Solo "hacer que las clases y los métodos sean lo más pequeños posible" es, en mi opinión, equivocado. El verdadero desafío es, como señala @c_maker, proporcionar buenas abstracciones. Su ejemplo de agrupar dos números juntos es excelente, por ejemplo, si está trabajando en una implementación de aritmética de números complejos, o si en un sistema Unix necesita referirse a un contexto de usuario / grupo. Tiene muy poco sentido si los números representan, por ejemplo, un ID de factura y un ID de producto que se agregarán a esa factura.

un CVn
fuente
0

Es un buen consejo, pero debe implementarse de manera algo inteligente. Definitivamente no lo sigas a ciegas.

Cuando miro mi código, sé si un método es demasiado grande. Si está haciendo demasiado y sería demasiado difícil de leer, entonces es tiempo de refactorización.

Aquí hay un buen ejemplo: tiene un bucle y tiene quizás 60 líneas de código en ese método. En ese caso, probablemente sea hora de refactorizar porque es probable que esté haciendo demasiado en ese método.

Pero, no es una regla dura y rápida. Es solo algo que puedes aprender haciendo. Y, otros desarrolladores con los que está trabajando no siempre están de acuerdo y pueden llamarlo en una revisión de código o lo que sea.

Alan Delimon
fuente
Nunca haga que los métodos sean más pequeños, siga SRP y automáticamente hará el trabajo.
Vinay Prajapati
0

El tío Bob dice que debes refactorizar / dividir / extraer tus métodos hasta que sea imposible hacerlos más pequeños . Esto generalmente termina en tener varios métodos con 3 o 4 líneas cada uno. Cuando obtienes demasiados métodos, tienes que hacer más clases.

Si intenta seguir SRP y un nivel de abstracción por método, estas reglas le serán útiles. Al menos me sirven bien. Apuntar a "lo más pequeño posible" me da métodos pequeños razonables, ya que generalmente no alcanzo el objetivo.

Y siempre es más fácil entender clases más pequeñas. Adelante, lee "Código limpio"

Peter Kofler
fuente