Escuché mucho sobre cómo mantener cortos los métodos y escuché a muchos programadores decir que usar etiquetas #region dentro de un método es una señal segura de que es demasiado largo y debe ser refactorizado en múltiples métodos. Sin embargo, me parece que hay muchos casos en los que separar el código con etiquetas #region dentro de un método es la solución superior para refactorizar en múltiples métodos.
Supongamos que tenemos un método cuyo cálculo se puede separar en tres fases bastante distintas. Además, cada una de estas etapas solo es relevante para el cálculo de este método, por lo que extraerlas en nuevos métodos no nos permite reutilizar el código. ¿Cuáles son, entonces, los beneficios de extraer cada fase en su propio método? Por lo que puedo decir, todo lo que ganamos es cierta legibilidad y un alcance variable separado para cada fase (lo que ayudará a evitar que las modificaciones de una fase en particular rompan accidentalmente otra fase).
Sin embargo, ambos se pueden lograr sin extraer cada fase en su propio método. Las etiquetas de región nos permiten contraer el código en un formulario que sea igual de legible (con el beneficio adicional de que ya no tenemos que dejar nuestro lugar en este archivo si decidimos expandir y examinar el código), y simplemente envolver cada fase en {}
crea su propio alcance para trabajar.
El beneficio de hacerlo de esta manera es que no contaminamos el alcance del nivel de clase con tres métodos que en realidad solo son relevantes para el funcionamiento interno de un cuarto método. Refactorizar inmediatamente un método largo en una serie de métodos cortos me parece el código reutilizable equivalente a la optimización prematura; está introduciendo una complejidad adicional para abordar un problema que en muchos casos nunca surge. Siempre puede extraer una de las fases en su propio método más adelante si surge la oportunidad de reutilizar el código.
Pensamientos?
fuente
#region
etiquetas , sino que apago el plegado de código en Visual Studio por completo. No me gusta el código que intenta esconderse de mí.Respuestas:
Lo único que debería importarle es que su código sea utilizable, no reutilizable. Un mono puede transformar el código utilizable en código reutilizable, si hay alguna transformación por hacer.
El argumento "Necesito esto solo aquí" es pobre, para decirlo cortésmente. La técnica que está describiendo a menudo se conoce como la técnica de los titulares y generalmente está mal vista.
También relevante: pensamientos de Jeff Atwoods sobre el plegado de código
fuente
El problema no son las regiones en los métodos, sino el caso cuando hay una necesidad (o incluso un uso) de poner regiones en los métodos.
Habiendo tenido que depurar muchos métodos de línea 200-300, puedo decirte que no se lo desearía a nadie. Si está escribiendo y cuidando su propio código, está bien, haga lo que quiera. Pero una vez que alguien más lo mira, debe quedar claro de inmediato qué está haciendo un método.
No, eso no es lo suficientemente bueno. Divídalo en regiones todo lo que quiera, pero todavía estoy sacudiendo mi cabeza solo de pensarlo.
Si interrumpes los métodos obtienes muchos beneficios:
///
) y entrar en la descripción, parámetros, tipo de retorno, y tambiénexception
,example
,remarks
nodos al detalle esos escenarios. Ahí va, ¡para eso está!{}
, pero ¿tengo que verificar todos los métodos para asegurarme de que no hizo 'trampa'? ¿Es esto lododgyObject
que estoy usando aquí solo porque se usa en esta región, o vino de otro lado? Si estuviera en mi propio método, podría ver fácilmente si me lo pasaron o si lo creé yo mismo (o más bien, si lo creaste).TurnThingsUpsideDown
método falló, probablemente esté fallando al convertir una cosa mala" es mucho mejor que "Oh, elDoEverything
método falló, podrían haber sido 50 cosas diferentes y tendré que cavar durante una hora para encontrarlo" .Todo esto es antes de cualquier problema de reutilización o improbabilidad. Los métodos separados adecuadamente obviamente facilitan la reutilización y también le permiten reemplazar fácilmente un método que no funciona (demasiado lento, demasiado defectuoso, dependencia modificada, etc.). ¿Alguna vez has intentado refactorizar alguno de estos enormes métodos? No hay forma de saber que lo que estás cambiando no afectará a nada más.
Encapsule adecuadamente su lógica en métodos de tamaño razonable. Sé que es fácil para ellos salir de control, y argumentar que no vale la pena rediseñar una vez en ese momento es otro problema. Pero debe aceptar el hecho de que no hay daño y al menos un beneficio potencial al tener métodos adecuadamente encapsulados, bien escritos y de diseño simple.
fuente
Si su método es lo suficientemente complejo como para que pueda separarse en tres fases distintas, entonces no solo deberían ser tres métodos separados ... sino que su método debería ser una clase separada, dedicada a ese cálculo.
"¡Pero entonces mi clase tendrá un solo método público!"
Tienes razón, y no hay nada de malo en eso. La idea del principio de responsabilidad única es que su clase hace una cosa .
Su clase puede llamar a cada uno de los tres métodos por turno y devolver el resultado. Una cosa.
Como beneficio adicional, ahora su método es comprobable porque ya no es un método privado.
Pero no importa una clase; en realidad debería tener cuatro : uno para cada una de las partes de su método, más uno que tome cada una de las tres como una dependencia y las llame en el orden correcto, devolviendo el resultado.
Esto hace que sus clases sean aún más comprobables. También le facilita cambiar una de esas tres piezas. Simplemente escriba una nueva clase heredada de la anterior y anule el comportamiento modificado. O cree una interfaz para el comportamiento de cada una de sus tres piezas; y luego para reemplazar uno, simplemente escriba una nueva clase implementando esa interfaz y sustitúyala por la anterior en la configuración del contenedor de inyección de dependencia.
¿Qué? ¿No estás usando inyección de dependencia? Bueno, probablemente aún no haya visto la necesidad, porque no está siguiendo el principio de responsabilidad única. Una vez que comience, encontrará que la forma más fácil de darle a cada clase sus dependencias es usar un contenedor DI.
EDITAR :
Bien, dejemos de lado la pregunta de refactorización. El propósito de
#region
es ocultar el código , lo que significa principalmente código que no necesita ser editado bajo ninguna circunstancia normal. El código generado es el mejor ejemplo. Debe estar oculto en regiones porque normalmente no es necesario editarlo. Si lo necesita, entonces el acto de expandir una región le da un poco de advertencia de estilo "Aquí hay dragones" para asegurarse de que sabe lo que está haciendo.Por lo tanto, diría
#region
que no debe usarse en medio de un método. Si abro un método, quiero ver el código. Usar #region me da otro nivel de ocultación que no necesito, y eso se convierte en una molestia: desarrollo el método ... y todavía no puedo ver ningún código.Si le preocupa que las personas vean la estructura del método (y se niega a refactorizarlo), agregue comentarios de banner como este:
Esto ayudará a alguien que navega por el código a ver las partes individuales de su método sin tener que lidiar con
#region
etiquetas expandibles y colapsadas .fuente
ctrl+n
Creo que el ejemplo que da en su argumento es menos acerca de YAGNI (no lo va a necesitar) y más acerca de escribir un código de calidad adecuado que sea fácilmente mantenible.
En los primeros cursos de programación, aprendemos que si un método tiene una longitud de 700 LOC, es probable que sea demasiado grande y ciertamente sería un gran problema intentarlo y depurarlo.
En segundo lugar, si escribo los métodos A, B y C que solo se usan dentro del método D, entonces puedo realizar pruebas unitarias AB y C más fácilmente independientemente de D, lo que permite pruebas unitarias más robustas en los 4 métodos.
fuente
Esos son dos beneficios. Pero lo importante, para mí de todos modos, es la depuración . Si tiene que rastrear ese código, es mucho más simple poder pasar por encima de dos de las tres secciones y solo rastrear en el que le interesa. Refactorizar en métodos más pequeños permite esto; las etiquetas de región no.
fuente
ctrl-f10
- corre al cursorMi regla personal es que si un método es más largo que una pantalla, digamos 40 líneas, es demasiado largo. Si una clase tiene más de 500 líneas, es demasiado grande. A veces rompo estas reglas, ocasionalmente incluso por un gran múltiplo, pero generalmente me arrepiento dentro del año.
Incluso un método de 20 a 30 líneas se está alargando un poco en la mayoría de los casos. Entonces, diría que usar regiones en un método suele ser una mala idea, simplemente porque casi nunca tendría sentido colapsar una región de 20 a 30 líneas en múltiples subregiones.
Desglosar las funciones que son largas según esta definición tiene al menos dos beneficios:
Puede poner un nombre a lo que están haciendo esas subfunciones, lo que aclara su pensamiento actual y simplifica la tarea de los mantenedores posteriores.
La descomposición en funciones más pequeñas lo obliga a pasar solo los parámetros que esas funciones más pequeñas necesitan, por lo que el alcance de los datos que requieren y modifican es muy claro. Esto supone que no está accediendo y modificando el estado del objeto en cien funciones de hoja diferentes, lo que también desalientaría.
En mi experiencia, estas reglas producen código que es más fácil de escribir sin cometer errores comunes y se puede entender y modificar más adelante sin romper comportamientos sutiles. No importa si la persona que tiene que entender / modificar el código es otra persona, o yo mismo después de haber dormido y olvidado todo.
Por lo tanto, consideraría que las regiones en los métodos son un "olor a código" que indica que se están aplicando prácticas insostenibles. Como siempre, podría haber excepciones, pero ocurren con tan poca frecuencia que casi no vale la pena discutirlas.
fuente
Aquí vamos de nuevo ... Hay muchos otros temas aquí sobre programadores que han terminado en la misma discusión.
Señala algunos argumentos muy interesantes relacionados con funciones cortas. No es una declaración popular, pero estoy contigo en esto . Después de haberlo discutido muchas veces antes, tengo la impresión de que la discusión generalmente se reduce a si se enfoca principalmente en la encapsulación adecuada o lleva el desarrollo impulsado por pruebas al máximo. Estos son los dos principales contendientes en lo que parece estar resultando en otra guerra santa, y me temo que estamos en el lado de baja potencia.
Sin embargo ...
La solución en mi opinión definitivamente no es envolver las 'fases' en las regiones. El plegado de código se usa para barrer el código debajo de la alfombra. Deje el código allí como está, ¡podría recordarle que tal vez desee refactorizarlo más adelante! Para relacionarlo con un argumento en su pregunta: ¿cómo podrá ver una oportunidad para reutilizar el código si no ve ningún código? Los segmentos largos de código deberían ser exactamente eso, una espina en el ojo que hace que quieras refactorizarlo.
Como un reemplazo apropiado para las regiones, sugiero usar párrafos de código como Alex Papadimoulis los nombra en un comentario . Es posible que ya esté utilizando un enfoque similar. Son simplemente bloques de código con un encabezado de comentario, explicando lo que hace todo el bloque. Tiene la legibilidad de las funciones, pero puede usar oraciones espaciadas normalmente en inglés y no pierde ninguna encapsulación.
fuente
Aunque estoy de acuerdo en que generalmente es mejor refactorizar el código que usarlo
#region
, no siempre es posible.Para apoyar esa afirmación, permítanme dar un ejemplo.
Es fácil reajustar las regiones para alterar el orden o ampliar cuando se agregan campos adicionales a la clase. De todos modos, se requieren comentarios para ver rápidamente cómo se supone que funciona el pedido. Y, sobre todo: no veo cómo la refactorización ayudará a la legibilidad en este caso.
Sin embargo, esas excepciones son raras. Por lo general, es posible refactorizar, como dicen muchas de las otras respuestas.
fuente
No creo que haya una sola respuesta de por qué ciertas personas o equipos deciden no usarla,
#region
pero si tuviera que enumerar algunas, estas serían las principales razones que he visto.fuente