¿Es común usar clases parciales para lograr 'modularidad'?

24

Recientemente me encontré con una situación en nuestra base de código donde un equipo diferente creó una 'clase de dios' que contiene alrededor de 800 métodos, divididos en 135 archivos como una clase parcial.

Le pregunté al otro equipo sobre esto. Si bien mi reacción instintiva fue atacarlo desde la órbita, insisten en que es un buen diseño, una práctica común, y que promueve la 'modularidad' y la 'facilidad de implementación' porque los nuevos desarrolladores pueden atornillar la funcionalidad sin casi ningún conocimiento del resto del sistema.

¿Es esto realmente una práctica común o de alguna manera una buena idea? Me inclino a tomar medidas inmediatas para derribar a esta bestia (o al menos evitar que siga creciendo), pero estoy dispuesto a creer que estoy equivocado.

Joshua Smith
fuente
66
¡mátalo con fuego! Pero en serio, ¿puede el otro equipo proporcionar alguna cita para esta supuesta práctica común?
MattDavey
1
Ninguna. Estoy seguro de que están haciendo humo, pero estoy tratando de hacer mi diligencia debida antes de soltar el martillo.
Joshua Smith
¿Cuál es su razonamiento para no hacer esto todo el tiempo?
JeffO
3
Pídales que describan, en una oración, qué tienen en común los 800 métodos en 135 archivos. Debería ser posible responder eso para cualquier clase sensata y razonable.
Carson63000
3
@ Carson63000 "Realiza todas las funciones requeridas del proyecto". ahí está tu única oración
Ryathal

Respuestas:

39

Esto no es de ninguna manera una buena idea.

Existen clases parciales para ayudar al diseñador de formularios. Usarlos por cualquier otro motivo (y posiblemente para su propósito previsto, pero es un asunto diferente) es una mala idea, ya que conduce a clases infladas que son difíciles de leer y comprender.

Míralo de esta manera: si una clase de dios con 800 métodos en un archivo, donde sabes dónde está todo, es algo malo, y creo que todos estarían de acuerdo en que es así, entonces, ¿cómo puede una clase de dios con 800 métodos? distribuido en 135 archivos, donde no sabes dónde es posible que todo sea algo bueno.

Mason Wheeler
fuente
1
Principalmente estoy de acuerdo, pero creo que puede haber algunos casos raros en los que partialpuede ser útil incluso sin el código generado. ¿Quizás cuando tienes algo como una clase anidada?
svick
1
@svick: las clases parciales son interesantes, pero generalmente no son necesarias. No estoy seguro de por qué dividir una clase en archivos separados sería útil cuando hay clases anidadas. A menos que desee la clase anidada en su propio archivo físico. En ese caso ... maaaaybe está bien. ;)
FrustratedWithFormsDesigner
55
A veces uso clases parciales para implementaciones explícitas de interfaz, especialmente algo como System.IConvertible. De alguna manera parece más limpio que poner una # región masiva en mi clase.
MattDavey
1
El comentario de la clase anidada es realmente una buena idea, nunca pensé en eso. Aunque ... eso tiene más que ver con la organización que con la 'modularidad'
Sheldon Warkentin
1
"Existen clases parciales para ayudar al diseñador de formularios". Correcto en general, pero agregaría "... y otros generadores de código". Estoy de acuerdo con el resto de su respuesta;)
Silas
14

Entonces la pregunta era:

¿Es esto realmente una práctica común o de alguna manera una buena idea?

Entre las respuestas disponibles actualmente se encuentra un rotundo no . Así que hay algunas otras cosas en las que podría intervenir, como; incluso el código de procedimiento puede hacerse modular e incluir todo, pero el fregadero de la cocina no es la forma de lograr la modularidad. Lo que sí hace una clase gigante dividida en parciales, todo se suma en un gran desastre.

Sin embargo, esa pregunta es una pista falsa para la parte crítica real de lo que se ha perdido; ya que el OP también tiene lo siguiente que decir sobre la situación:

(...) Si bien mi reacción intestinal fue sacudirlo desde la órbita, insisten ...

(...) Me inclino a tomar medidas inmediatas para derribar a esta bestia (o al menos evitar que siga creciendo), pero estoy dispuesto a creer que estoy equivocado.

¡CALMA!

Esto es algo que haría que mi monóculo figurativamente hablando cayera en mi taza de té figurativa.

He estado en situaciones similares y déjame decirte: NO caigas en la urgencia de hacerlo. Claro, puedes dejar el Nuke Hammer of Justice en el equipo, pero antes de hacerlo, por favor hazte el siguiente enigma:

¿Qué pasará si le dice al equipo que su código chupa y al cabrón ?

(... o algo así pero de manera menos ofensiva, en realidad no importa porque se ofenden independientemente de lo que hagas si decides ir con toda su fuerza)

¿Cuál es la situación actual con la base del código? ¿Está funcionando? Entonces tendrás grandes problemas para explicarles a sus clientes que su código esencialmente apesta . No importa qué razones tengan: mientras funcione, a la mayoría de los clientes no les importa cómo está organizado el código.

También ponte en sus zapatos, ¿qué harían? Déjame divertirte con el siguiente resultado muy posible:

Miembro del equipo n. ° 1: "Entonces este tipo nos dice que lo hemos estado haciendo mal durante los últimos años".

Miembro del equipo # 2 y # 3: "Qué idiota".

Miembro del equipo influyente # 4: "No se preocupe por eso, simplemente iré a la gerencia y lo reportaré como un acoso".

¿Ves lo que el miembro del equipo influyente # 4 hizo allí? Fue a la gerencia y redujo su karma en la empresa. Él podría ser estadounidense-italiano, diciéndole a todos que no se preocupen por eso, pero entonces sería racista al respecto.

Pintar al equipo infractor en una esquina y dejarlos admitir que lo hicieron mal durante tanto tiempo también es una mala idea y lleva a lo mismo. Perderás el respeto y algo de karma político de oficina.

Incluso si logró que un grupo de personas firmen esto, para "enseñarle una lección al equipo", recuerde que lo está haciendo con personas bastante inteligentes que aparentemente hacen algunas cosas. Una vez que el código será reescrito / refactorizado / tratado / lo que sea que surja y surjan problemas, usted será responsable de ser el iniciador .

Ser adversario sobre situaciones como esta es principalmente un juego de perder / perder, ya que corre el riesgo de convertirse en un círculo vicioso de juegos de culpa. Este es un resultado subóptimo para esta situación. Incluso si ganas, de repente te entregan el desastre que otra persona hizo.

Hay otras formas (mucho más maduras)

Una vez tuve una situación similar, pero luego recibí una flecha en la rodilla. Entonces, después de un tiempo con esa repentina flecha que altera la carrera en mi mente, recibí un libro Driving Technical Change de Terrence Ryan . Enumera varios patrones de escépticos, el tipo de personas que no actúan sobre buenas ideas. Es muy probable que sean aplicables en el caso del OP:

  • Los desinformados: realmente no sabían que había otras formas o simplemente no entendían. Los desarrolladores junior generalmente encajan en esta categoría, pero no necesariamente. (Para ser honesto: he conocido desarrolladores junior que serían más brillantes que esto).
  • El rebaño: sabían mejores técnicas que usar clases parciales, pero no sabían que estaban permitidos.
  • The Cynic: simplemente les gusta argumentar que tener clases parciales es mejor que su idea solo por discutir. Es fácil hacerlo en una multitud en lugar de pararse frente a una multitud.
  • The Burned: por alguna extraña razón, no les gusta crear nuevas clases, lo más probable es que lo perciban como demasiado difícil.
  • The Time Crunched: están tan ocupados que no pueden molestarse en arreglar su código.
  • The Boss - Piensan: "Bueno, funciona, ¿por qué molestarse?"
  • The Irrational: Ok, están completamente locos.

El libro continúa con una lista de estrategias, etc., pero en el caso del OP es una cuestión de persuasión. Ir a la cabeza con los hechos sobre el antipatrón no es suficiente.

Si le interesa aumentar la calidad del código, al menos brinde al equipo infractor la oportunidad de reiterar y rectificar su propio desorden . Personalmente, trataría de influirlos escuchando y haciendo preguntas principales, dejar que cuenten su historia:

  • ¿Qué está haciendo exactamente su clase de dios?
  • ¿Han tenido algún problema? ¿Tienen algún error? Sugiera soluciones sanas sin decirles que lo hagan.
  • Si usted es un usuario de esta clase de dios como API: ¿Hay formas más simples de usar el código que usar todo? Sugiera ejemplos más simples, vea cómo reaccionan.
  • ¿Se puede cambiar alguna funcionalidad con otra, sin tener que escribir la función?
  • ¿Necesitan alguna capacitación? ¿Puede convencer a la gerencia para que lo haga o almorzar sobre patrones y prácticas?

... y así. Déles pequeñas sugerencias para que puedan avanzar. Lleva tiempo y necesitará un poco de grasa en el codo, pero la paciencia y el trabajo duro son una virtud, ¿verdad?

Spoike
fuente
Esta es una respuesta muy perspicaz. Si es un desarrollador nuevo, debe comprender esto. Los desarrolladores más experimentados se dan cuenta de esto después de varios años, algunos nunca lo hacen.
FishySwede
6

La página de Clases y métodos parciales de MSDN sugiere dos situaciones para usar clases parciales:
1. Para dividir una clase gigante en múltiples archivos separados.
2. Tener un lugar para colocar el código fuente generado automáticamente.

2 es muy utilizado por Visual Studio (por ejemplo, para archivos aspx y winforms). Este es un uso razonable de clases parciales.

1 es lo que está haciendo tu equipo. Diría que usar clases parciales es una forma perfectamente razonable de lograr la modularidad cuando se tienen clases gigantes, pero tener clases gigantes en sí mismo no es razonable. En otras palabras, tener una clase gigante es una mala idea, pero si vas a tener una clase gigante, las clases parciales son una buena idea.

Aunque si puede dividir inteligentemente una clase en archivos separados para que trabajen diferentes usuarios, ¿no puede dividirla en clases separadas?

Brian
fuente
+1 para "¿no puedes dividirlo en clases separadas?". Esto es exactamente lo que estamos sugiriendo. Parece sentido común que debería haberse hecho así originalmente.
Joshua Smith
4

Entonces, al final, están haciendo un desarrollo procesal normal sin ninguna pieza de OOP. Tienen un espacio de nombres global con todos los métodos, variables y demás.

O persuadirlos de que lo están haciendo mal o salir de allí.

Eufórico
fuente
1

Una clase de utilidad contiene métodos que no se pueden combinar con otros métodos para crear una clase. Si tiene más de 800 métodos, divididos en 135 archivos, parece probable que alguien haya logrado encontrar algunos métodos comunes ...

El hecho de que tenga una clase de utilidad no significa que no pueda tener otra clase de utilidad.

Incluso si tiene 800 métodos en su mayoría no relacionados, la solución no es una gran clase y muchos archivos. La solución es un espacio de nombres, algunos subespacios de nombres y muchas clases pequeñas. Esto es un poco más de trabajo (tienes que encontrar un nombre para la clase y el método). Pero hará que su vida sea más fácil cuando llegue el momento de limpiar este desorden, y mientras tanto hará que intellisense sea más fácil de usar (es decir, más fácil descubrir dónde es un método para usarlo).

Y no, esto no es común (más el número de archivos que el número de funciones gratuitas).

jmoreno
fuente
0

No me gusta esto en absoluto. Sin embargo, tal vez las clases parciales tuvieron sentido para los desarrolladores durante el desarrollo porque permitieron el desarrollo concurrente de este gran número de métodos, especialmente si no hay mucha dependencia entre ellos.

Otra posibilidad es que esas clases parciales se construyeron para modificar una clase principal generada automáticamente. Si este es el caso, uno no debe tocarlos, de lo contrario, el código personalizado se eliminaría al volver a generar.

No estoy seguro de que alguien pueda mantener esto con facilidad sin algún estudio. Ahora, si lo matas, la cantidad de métodos no disminuirá. La cantidad de métodos y complejidad, para mí, es el verdadero problema. Si los métodos realmente pertenecen a la clase, entonces tener 1 archivo enorme no te facilitará la vida, especialmente en mantenimiento, de hecho, puede ser más propenso a errores exponer todo este código a errores tontos como la búsqueda con comodines y reemplazar.

Así que ten cuidado y justifica la decisión de matar. Además, considere qué pruebas se requerirán.

Ninguna posibilidad
fuente
0

Está perfectamente bien desde una perspectiva de diseño práctica, suponiendo que los 135 archivos realmente agrupen métodos similares a lo que harían las clases tradicionales. Es solo un promedio de 6 métodos por archivo. Definitivamente no es la forma más popular o tradicional de diseñar un proyecto. Intentar cambiarlo solo creará un montón de problemas y la enfermedad no tendrá ningún beneficio real. Hacer que el proyecto se ajuste a los estándares OO creará tantos problemas como se resuelvan. Es un asunto completamente diferente si los archivos múltiples en realidad no proporcionan separaciones significativas.

Ryathal
fuente
3
Refactorizar el código de procedimiento en OO generalmente tiene ese problema: creo que arreglar esto será una tarea enorme y enseñarle al equipo a codificar correctamente aún más, además de que se culpará a Joshua de todo lo que suceda durante el próximo año (y más allá ) si los convence de refactorizar. Es por eso que nadie presiona demasiado para hacer refactores como este (al menos no una vez que han visto los resultados). Además, si crees que es un buen diseño, bueno, revisa esta respuesta en 5 años y cuéntanos qué piensas entonces (parece que vuelvo a aprender todo lo que sé sobre diseño cada 5 años más o menos).
Bill K
@BillK si espera diez años, lo que sabe probablemente será la filosofía de diseño actual "en".
Ryathal
Los 135 archivos generalmente agrupan métodos relacionados, pero eso (para mí) todavía no lo convierte en una buena idea. Quiero probar este sistema, pero tropezar / burlarse de la hidra del método 800 va a ser un dolor feo en el culo.
Joshua Smith
@Ryathal no es lo que está "dentro", es lo que crees que es un buen diseño (por buenas razones) y luego, a medida que practicas y mejoras, te das cuenta de que no es una idea tan buena como pensabas. Parece que sucede cada 5 años más o menos, y una vez que reconocí que atenúa mi respuesta a los comentarios de algunas personas porque me doy cuenta de que en realidad son excelentes diseñadores que están (como todos nosotros) en el proceso de mejorar para siempre nuestras prácticas. El único programador que me preocupa es uno que no pensó que podrían mejorar el código que habían escrito hace 5 años.
Bill K
0

Más allá de las respuestas ya señaladas, las clases parciales pueden ser útiles en un diseño en capas donde desea organizar la funcionalidad que cruza su jerarquía de clases en archivos específicos de capa separados. Esto permite utilizar el explorador de soluciones para navegar por la funcionalidad por capa (por organización de archivos) y la vista de clase para navegar por la funcionalidad por clase. Preferiría usar un lenguaje que admita mixins y / o rasgos, pero las clases parciales son una alternativa razonable si se usan con moderación, y no deberían ser un reemplazo para un buen diseño de jerarquía de clases.

Sean McDirmid
fuente