C # permite el uso de #region
/ #endregion
palabras clave para hacer que las áreas de código se puedan contraer en el editor. Cada vez que hago esto, lo hago para ocultar grandes porciones de código que probablemente podrían refactorizarse en otras clases o métodos. Por ejemplo, he visto métodos que contienen 500 líneas de código con 3 o 4 regiones solo para que sea manejable.
Entonces, ¿el uso juicioso de las regiones es un signo de problemas? A mí me parece así.
c#
code-smell
Craig
fuente
fuente
Respuestas:
Un olor a código es un síntoma que indica que hay un problema en el diseño que potencialmente aumentará el número de errores: este no es el caso para las regiones, pero las regiones pueden contribuir a crear olores de código, como los métodos largos.
Ya que:
Las regiones son antipatrones. Requieren más trabajo que no aumenta la calidad o la legibilidad del código, que no reduce la cantidad de errores y que solo puede hacer que el código sea más complicado de refactorizar.
No use regiones dentro de los métodos; refactorizar en su lugar
Los métodos deben ser cortos . Si solo hay diez líneas en un método, probablemente no usaría regiones para ocultar cinco de ellas cuando trabaje en otras cinco.
Además, cada método debe hacer una sola cosa . Las regiones, por otro lado, están destinadas a separar cosas diferentes . Si su método hace A, entonces B, es lógico crear dos regiones, pero este es un enfoque incorrecto; en su lugar, debe refactorizar el método en dos métodos separados.
El uso de regiones en este caso también puede dificultar la refactorización. Imagina que tienes:
El colapso de la primera región para concentrarse en la segunda no solo es arriesgado: podemos olvidarnos fácilmente de la excepción que detiene el flujo (podría haber una cláusula de protección con una
return
, que es aún más difícil de detectar), sino que también tendría un problema si el código debe ser refactorizado de esta manera:Ahora, las regiones no tienen sentido, y no es posible leer y comprender el código en la segunda región sin mirar el código en la primera.
Otro caso que a veces veo es este:
Es tentador usar regiones cuando la validación de argumentos comienza a abarcar decenas de LOC, pero hay una mejor manera de resolver este problema: la utilizada por el código fuente de .NET Framework:
No use regiones fuera de los métodos para agrupar
Algunas personas los usan para agrupar campos, propiedades, etc. Este enfoque es incorrecto: si su código es compatible con StyleCop, entonces los campos, propiedades, métodos privados, constructores, etc. ya están agrupados y son fáciles de encontrar. Si no es así, es hora de comenzar a pensar en aplicar reglas que garanticen la uniformidad en su base de código.
Otras personas usan regiones para ocultar muchas entidades similares . Por ejemplo, cuando tiene una clase con cien campos (que genera al menos 500 líneas de código si cuenta los comentarios y el espacio en blanco), puede verse tentado a colocar esos campos dentro de una región, colapsarlos y olvidarse de ellos. Nuevamente, lo estás haciendo mal: con tantos campos en una clase, deberías pensar mejor en usar la herencia o cortar el objeto en varios objetos.
Finalmente, algunas personas se sienten tentadas a usar regiones para agrupar cosas relacionadas : un evento con su delegado, o un método relacionado con IO con otros métodos relacionados con IO, etc. En el primer caso, se convierte en un desastre que es difícil de mantener , Lea y entienda. En el segundo caso, el mejor diseño probablemente sería crear varias clases.
¿Hay un buen uso para las regiones?
No. Hubo un uso heredado: código generado. Aún así, las herramientas de generación de código solo tienen que usar clases parciales en su lugar. Si C # tiene soporte de regiones, es principalmente porque este uso heredado, y porque ahora que demasiadas personas usan regiones en su código, sería imposible eliminarlas sin romper las bases de código existentes.
Piensa en ello como en
goto
. El hecho de que el idioma o el IDE admitan una función no significa que deba usarse a diario. La regla StyleCop SA1124 es clara: no debe usar regiones. Nunca.Ejemplos
Actualmente estoy haciendo una revisión del código del código de mi compañero de trabajo. La base de código contiene muchas regiones, y en realidad es un ejemplo perfecto de cómo no usar regiones y por qué las regiones conducen a un código incorrecto. Aquí hay unos ejemplos:
4 000 monstruo LOC:
Recientemente leí en algún lugar de Programmers.SE que cuando un archivo contiene demasiados
using
s (después de ejecutar el comando "Eliminar usos no utilizados"), es una buena señal de que la clase dentro de este archivo está haciendo demasiado. Lo mismo se aplica al tamaño del archivo en sí.Mientras revisaba el código, me encontré con un archivo de 4 000 LOC. Parecía que el autor de este código simplemente copiaba y pegaba el mismo método de 15 líneas cientos de veces, cambiando ligeramente los nombres de las variables y el método llamado. Una expresión regular simple permitió recortar el archivo de 4 000 LOC a 500 LOC, simplemente agregando algunos genéricos; Estoy bastante seguro de que con una refactorización más inteligente, esta clase puede reducirse a unas pocas docenas de líneas.
Al usar regiones, el autor se animó a ignorar el hecho de que el código es imposible de mantener y está mal escrito, y a duplicar en gran medida el código en lugar de refactorizarlo.
Región "Do A", Región "Do B":
Otro excelente ejemplo fue un método de inicialización de monstruos que simplemente realizó la tarea 1, luego la tarea 2, luego la tarea 3, etc. Hubo cinco o seis tareas que fueron totalmente independientes, cada una inicializando algo en una clase contenedor. Todas esas tareas se agruparon en un método y se agruparon en regiones.
Esto tenía una ventaja:
Los problemas, por otro lado, fueron múltiples:
No era obvio si había dependencias entre las regiones. Con suerte, no hubo reutilización de variables; de lo contrario, el mantenimiento podría ser una pesadilla aún más.
El método era casi imposible de probar. ¿Cómo podría saber fácilmente si el método que hace veinte cosas a la vez las hace correctamente?
Región de campos, región de propiedades, región de constructor:
El código revisado también contenía muchas regiones que agrupaban todos los campos, todas las propiedades, etc. Esto tenía un problema obvio: el crecimiento del código fuente.
Cuando abre un archivo y ve una lista enorme de campos, está más inclinado a refactorizar la clase primero y luego trabajar con el código. Con las regiones, tienes el hábito de colapsar cosas y olvidarte de ellas.
Otro problema es que si lo haces en todas partes, te encontrarás creando regiones de un bloque, lo que no tiene ningún sentido. Este fue realmente el caso en el código que revisé, donde había muchos que
#region Constructor
contenían un constructor.Finalmente, los campos, propiedades, constructores, etc. ya deberían estar en orden . Si lo son y coinciden con las convenciones (constantes que comienzan con una letra mayúscula, etc.), ya está claro en qué parte del tipo de elementos se detiene y comienza otro, por lo que no es necesario crear regiones explícitamente para eso.
fuente
¡Es increíble para mí cuántas personas odian las regiones con tanta pasión!
Estoy completamente de acuerdo con muchas de sus objeciones: insertar código en un
#region
para ocultarlo es algo malo. Dividir una clase en#regions
cuándo debería refactorizarse en clases separadas es claramente un error. Usar un#region
para insertar información semántica redundante es, bueno, redundante.¡Pero ninguna de esas cosas significa que hay algo intrínsecamente malo con el uso de regiones en su código! Solo puedo suponer que las objeciones de la mayoría de las personas provienen de haber trabajado en equipos donde otros están inclinados a usar las funciones IDE como esta incorrectamente. Tengo el lujo de trabajar en la primaria por mi cuenta, y aprecio la forma en que las regiones han ayudado a organizar mi flujo de trabajo. Tal vez sea mi trastorno obsesivo compulsivo, pero no me gusta ver un montón de código en mi pantalla a la vez, sin importar cuán elegante y elegantemente escrito esté. Separar las cosas en regiones lógicas me permite colapsar el código que no me interesa para trabajar en el código que hago.preocuparse. No estoy ignorando el código mal escrito, no tiene sentido refactorizarlo más de lo que es, y la organización "meta" adicional es descriptiva, más que inútil.
Ahora que he pasado más tiempo trabajando en C ++, programando más directamente a la API de Windows, me encuentro deseando que el soporte para las regiones sea tan bueno como lo es para C #. Podría argumentar que el uso de una biblioteca GUI alternativa haría que mi código sea más simple o más claro, eliminando así la necesidad de eliminar el ruido de código irrelevante de la pantalla, pero tengo otras razones para no querer hacer eso. Soy lo suficientemente competente con mi teclado e IDE que expandir / colapsar el código subdividido en regiones toma menos de una fracción de segundo. El tiempo que ahorro en capacidad mental, tratando de limitar mi enfoque consciente solo al código en el que estoy trabajando actualmente, vale la pena. Todo pertenece en una sola clase / archivo, pero no todos pertenecen a mi pantalla al mismo tiempo.
El punto es que usar
#regions
para separar y dividir lógicamente su código no es algo malo que deba evitarse a toda costa. Como señala Ed, no es un "olor a código". Si su código huele mal, puede estar seguro de que no proviene de las regiones, sino de cualquier código que haya intentado enterrar en esas regiones. Si una función te ayuda a ser más organizado o a escribir mejor código, entonces digo que lo uses . Si se convierte en un obstáculo, o te encuentras usándolo incorrectamente, entonces deja de usarlo. Si lo peor llega a ser peor, y te ves obligado a trabajar en un equipo con personas que lo usan, entonces memoriza el atajo de teclado para desactivar el esquema del código: Ctrl+ M, Ctrl+P. Y deja de quejarte. A veces tengo la sensación de que esta es otra forma en que a los que quieren ser vistos como programadores "verdaderos" y "incondicionales" les gusta probar y demostrar su valía. No es mejor evitar las regiones que evitar la coloración de sintaxis. No te hace un desarrollador más machista.Dicho todo esto, las regiones dentro de un método son pura tontería. Cada vez que desees hacer eso, deberías refactorizar a un método separado. No hay excusas.
fuente
En primer lugar, ya no soporto el término "olor a código". Se usa con demasiada frecuencia y es utilizado por personas que no podrían reconocer un buen código si lo mordiera. De todos modos ...
Personalmente no me gusta usar muchas regiones. Me resulta más difícil obtener el código, y el código es lo que me interesa. Me gustan las regiones cuando tengo una gran porción de código que no es necesario tocar con mucha frecuencia. Aparte de eso, parecen interponerse en mi camino y regiones como "Métodos privados", "Métodos públicos", etc., me vuelven loco. Son similares a los comentarios de la variedad
i++ //increment i
.También agregaría que el uso de regiones no puede ser realmente un "antipatrón", ya que ese término se usa comúnmente para describir patrones de diseño / lógica de programa, no el diseño de un editor de texto. Esto es subjetivo; usa lo que funciona para ti. Nunca terminarás con un programa que no se puede mantener debido al uso excesivo de las regiones, de eso se tratan los antipatrones. :)
fuente
Sí, las regiones son un código de olor!
Estaría feliz de ver regiones eliminadas del compilador por completo. Cada desarrollador presenta su propio esquema de aseo inútil que nunca será de valor para otro programador. Tengo todo que ver con los programadores que desean decorar y embellecer a su bebé, nada que tenga ningún valor real.
¿Puedes pensar en un ejemplo en el que pensaste "caramba, me gustaría que mi colega haya usado algunas regiones aquí"?
A pesar de que puedo configurar mi IDE para expandir automáticamente todas las regiones, siguen siendo un dolor ocular y no leen el código real.
Realmente me importaría menos si todos mis métodos públicos están agrupados o no. ¡Felicidades, conoce la diferencia entre una declaración de variable y una inicialización, no es necesario mostrarla en código!
Aseo sin valor!
Además, si su archivo necesita y 'arquitectura de información' a través del uso de regiones, es posible que desee combatir el problema central: ¡Su clase es demasiado grande! Dividirlo en partes más pequeñas es mucho más beneficioso y, cuando se hace correctamente, agrega una verdadera semántica / legibilidad.
fuente
Personalmente uso regiones como una forma de agrupar varios tipos de métodos o partes de código.
Entonces, un archivo de código podría verse así al abrirlo:
No pongo regiones dentro de los métodos. En mi humilde opinión eso es una señal de código de olor. Una vez me encontré con un método que tenía más de 1200 líneas de largo y tenía 5 regiones diferentes. Fue un espectáculo aterrador!
Si lo está utilizando como una forma de organizar su código de una manera que acelere la búsqueda de cosas para otros desarrolladores, no creo que sea una señal de problemas. Si lo está utilizando para ocultar líneas de código dentro de un método, diría que es hora de repensar ese método.
fuente
El uso de
#region
bloques para hacer que una clase muy grande sea legible suele ser una señal de violación del Principio de responsabilidad única. Si se están utilizando para agrupar el comportamiento, entonces también es probable que la clase esté haciendo demasiado (una vez más violando SRP).Siguiendo con la línea de pensamiento "olor a código", los
#region
bloques no son olores de código en sí mismos, sino que son más "Febreze for code" en el sentido de que intentan ocultar olores. Si bien los he usado una tonelada en el pasado, a medida que comienzas a refactorizar, comienzas a ver menos porque terminan sin esconderse mucho.fuente
La palabra clave aquí es "juicioso". Es difícil imaginar un caso en el que poner una región dentro de un método sea juicioso; eso es muy probable que sea código oculto y pereza. Sin embargo, puede haber buenas razones para tener algunas regiones aquí y allá en el código.
Si hay muchas regiones, creo que es un olor a código. Las regiones son a menudo un indicio de un posible lugar para futuras refactorizaciones. Muchas regiones significan que alguien nunca está captando la indirecta.
Usados juiciosamente, proporcionan un buen punto medio entre la estructura de una sola clase con muchos métodos y la estructura de muchas clases con solo unos pocos métodos en cada uno. Son más útiles cuando una clase comienza a acercarse al punto en el que debería refactorizarse en varias clases, pero aún no está allí. Al agrupar métodos relacionados, facilito más adelante extraer un conjunto de métodos relacionados en su propia clase si continúan creciendo en número. Por ejemplo, si tengo una clase que se acerca a las 500 líneas de código, ese conjunto de métodos que usan 200 líneas de código en total reunidas en una región es probablemente una buena pieza para refactorizar de alguna manera, y esa otra región con 100 líneas de código en su Los métodos también pueden ser un buen objetivo.
Otra forma en que me gusta usar regiones es reducir uno de los efectos negativos de refactorizar un método grande: muchos métodos pequeños, concisos y fácilmente reutilizables por los que un lector tiene que desplazarse para llegar a otro método mayormente no relacionado. Una región puede ser una buena manera de metaencapsular un método y sus ayudantes para los lectores, por lo que alguien que esté trabajando con un aspecto diferente de la clase puede colapsarlos y descartar rápidamente esa parte del código. Por supuesto, esto solo funciona si sus regiones están realmente bien organizadas y esencialmente se utilizan como otra forma de documentar su código.
En general, encuentro que las regiones me ayudan a mantenerme organizado, me ayudan a "documentar" mi código y me ayudan a encontrar lugares para refactorizar mucho antes que si no uso regiones.
fuente
Utilizo principalmente regiones para clases de servidor CRUD para organizar los diversos tipos de operaciones. Incluso entonces, con gusto podría ir sin ellos.
Si se usa ampliamente, levantaría una bandera roja. Estaría atento a las clases que tienen demasiada responsabilidad.
En mi experiencia, un método con cientos de líneas de código es definitivamente un olor.
fuente
Mi regla general es: si tiene más de 5 regiones en un archivo, es un olor a código
Es decir, podría estar bien delinear el campo, los métodos, las propiedades y los constructores, pero si está comenzando a ajustar cualquier otro método en una región propia, algo está muy mal
... y sí, he estado en muchos proyectos donde ese es el caso, a menudo debido a los estándares de codificación deficientes, la generación de código o ambos. Se vuelve rápido tener que alternar todos los esquemas en Visual Studio para obtener una buena visión general del código.
fuente
LAS REGIONES TIENEN SU USO
Los he usado personalmente para eventos de interfaz de "codificación manual" antes para aplicaciones de formularios de Windows.
Sin embargo, en mi trabajo usamos un generador de código para manejar SQL y automáticamente usa regiones para ordenar sus tipos de métodos de selección, actualización, eliminación, etc.
Entonces, aunque no los uso a menudo, están perfectamente bien para eliminar grandes fragmentos de código.
fuente
Si tiene regiones en el código IN , ciertamente tiene un problema (salvo el caso del código generado). Poner regiones en el código es básicamente decir "refactorizar esto".
Sin embargo, hay otros casos. Una que me viene a la mente que hice hace un tiempo: una mesa con un par de miles de elementos precalculados. Es una descripción de la geometría, salvo un error en la tabla, nunca habrá una ocasión para mirarlo. Claro, podría haber obtenido los datos de un recurso o similar, pero eso impediría usar el compilador para facilitar la lectura.
fuente
En un proyecto reciente, había un método de línea 1700 con varias regiones incrustadas en él. Lo interesante es que las regiones demarcaron distintas acciones que se estaban realizando dentro del método. Pude hacer un refactor -> método de extracción en cada una de las regiones sin afectar la funcionalidad del código.
En general, las regiones utilizadas para ocultar el código de la placa de la caldera son útiles. Aconsejaría no usar regiones para ocultar propiedades, campos y similares, porque si son demasiado difíciles de ver cuando se trabaja dentro de la clase, probablemente sea una señal de que la clase debería desglosarse aún más. Pero como regla general, si está colocando una región dentro de un método, probablemente sea mejor extraer otro método que explique lo que está sucediendo que envolver ese bloque en una región.
fuente
¿Se pueden usar regiones en código de buena calidad? Probablemente. Apuesto a que lo son, en muchos casos. Sin embargo, mi experiencia personal me deja muy sospechoso: he visto regiones mal utilizadas casi exclusivamente. Yo diría que estoy cansado, pero aún optimista.
Puedo dividir aproximadamente el código que usa la región que he visto hasta la fecha en tres categorías:
Código factorizado deficientemente: la mayor parte del código que he visto usa regiones como una herramienta de factorización de los pobres. Por ejemplo, una clase que ha crecido hasta el punto en que tiene sentido especializarse para diferentes propósitos podría dividirse en regiones separadas, una para cada propósito.
Código escrito usando las bibliotecas incorrectas, y a veces el lenguaje incorrecto, para el dominio del problema A menudo, cuando un programador no está usando el conjunto correcto de bibliotecas para el dominio del problema, verá que el código se vuelve increíblemente detallado, con muchas pequeñas funciones auxiliares que realmente no pertenecen (probablemente pertenecen a su propia biblioteca).
Código escrito por estudiantes o recién graduados. Algunos programas y cursos parecen intentar inculcar a los estudiantes con el uso de regiones para todo tipo de propósitos extraños. Verá regiones que ensucian el código fuente hasta el punto donde la proporción de etiquetas de región a líneas de código está en el rango de 1: 5 o peor.
fuente
Yo diría que es un "olor a código".
Los antipatrones son generalmente problemas estructurales fundamentales en una pieza de software, mientras que las regiones, por sí mismas, solo causan un comportamiento desagradable en un editor. El uso de regiones no es realmente inherentemente malo, pero usarlas mucho, especialmente para ocultar fragmentos de código, puede indicar que hay otros problemas independientes y mayores que ocurren en otros lugares.
fuente
Solo uso regiones para una cosa (al menos no puedo pensar en otros lugares donde las uso): agrupar pruebas unitarias para un método.
Por lo general, tengo una clase de prueba por clase y luego agrupo las pruebas unitarias para cada método usando regiones que tienen el nombre del método. No estoy seguro si eso es un olor a código o algo así, pero dado que la idea básica es que las pruebas unitarias no necesitan cambiar a menos que se rompan porque algo cambió en el código, me resulta más fácil encontrar todas las pruebas para un método específico bastante rápido.
Puede que haya usado regiones para organizar el código en el pasado, pero no recuerdo la última vez que lo hice. Sin embargo, me quedo con mis regiones en las clases de pruebas unitarias.
fuente
Creo que son un anti patrón y francamente creo que deberían eliminarse. Pero si se encuentra en la desafortunada situación de trabajar en un lugar donde son estándar, Visual Studio ofrece una herramienta increíble para minimizar la cantidad que le gustaría vomitar cada vez que vea una región que odio #Regiones
Este complemento maximizará el tamaño de fuente de las regiones realmente pequeñas. También se expandirán para que no tenga que presionar ctr + m + l para abrir todas las regiones. No soluciona esta forma de código de cáncer, pero lo hace soportable.
fuente
Utilizo regiones para contener cada combinación de visibilidad y tipo de miembro. Entonces todas las funciones privadas van a una región, etc.
La razón por la que hago esto no es para poder plegar el código. Es porque tengo mi editor programado para poder insertar, por ejemplo, una referencia a un proxy:
en el código y haga que cada parte esté perfectamente metida en la región adecuada.
En este caso, la macro analizaría mi proyecto, me daría un cuadro de lista de proxies e inyectaría el código para el que quiero. Mi cursor ni siquiera se mueve.
Al comienzo de aprender C #, había considerado el uso de regiones para mantener la comunidad en común, pero esa es una propuesta impredecible porque no es una relación uno a uno en todo momento. Quién quiere preocuparse por un miembro utilizado por dos regiones, o incluso comenzar a dividir las cosas en esos términos.
El único otro tipo de segregación son los métodos: dividiré los métodos en Comandos, Funciones y Controladores, para tener una región para los comandos públicos, privados, etc., etc.
Esto me da granularidad, pero es una granularidad consistente e inequívoca en la que puedo confiar.
fuente
Las regiones son expresiones de preprocesador; en otras palabras, el compilador las trata como comentarios y básicamente las ignora. Son puramente una herramienta visual utilizada en Visual Studio. Por lo tanto, #region no es realmente un olor a código, porque simplemente no es código. El código de olfato es más bien el método de 800 líneas que tiene muchas responsabilidades diferentes incrustadas, etc. Entonces, si ve 10 regiones en un método, probablemente se esté utilizando para ocultar un código de olfato. Una vez dicho esto, los he visto utilizados de manera extremadamente efectiva para hacer que una clase sea más agradable a la vista y más navegable, ¡también en una clase muy bien escrita y estructurada!
fuente
Las regiones eran una idea organizativa ingeniosa, pero no tuvieron en cuenta algunas tendencias de los desarrolladores para querer sobrecategorizar todo, y en general innecesarias de acuerdo con la mayoría de las prácticas modernas de OOP ... son un "olor", en el sentido de que su uso a menudo indica que su clase / método es demasiado grande y debe ser refactorizado, ya que probablemente está violando la "S" de los principios SÓLIDOS ... pero como cualquier olor, no necesariamente significa que algo va mal.
Las regiones tienen más propósito en el código funcional en lugar del código orientado a objetos, IMO, donde tiene largas funciones de datos secuenciales que tiene sentido dividir, pero ha habido ocasiones en que personalmente las he usado en C #, y casi siempre enfóquese en el código que no necesita / desea mirar. Para mí, estas eran generalmente constantes de cadena SQL sin procesar en la base de código utilizada para NPoco o sus variantes. A menos que realmente te importe cómo llegan los datos para completar el objeto POCO a través de tu ORM, estos fueron completamente inútiles de ver ... y si te importaba, ¡oye, solo expande la región y BAM! Más de 150 líneas de alguna consulta SQL complicada para su placer visual.
fuente