¿Por qué la gente se opone tan fuertemente a las etiquetas #region en los métodos?

27

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?

jjoelson
fuente
44
Actualmente estoy trabajando con una clase que es bastante grande. Sigue el principio de responsabilidad única; todo en la clase es funcionalidad requerida. Tiene muchos métodos privados, principalmente debido a la refactorización. Utilizo #region para dividir estos métodos en categorías funcionales, lo que nos ha funcionado muy bien. Hay muchas otras clases en este proyecto que no requieren tal tratamiento. La herramienta adecuada para el trabajo correcto, digo.
Robert Harvey
44
@RobertHarvey, usarlos en una clase es diferente de usarlos dentro de un método.
CaffGeek
18
@ Chad: Ah, no me di cuenta de eso. Usarlos en un método parece un poco extremo. Si un método es tan largo que requiere #regiones, lo refactorizo ​​en métodos separados.
Robert Harvey
8
No es realmente una respuesta, pero no solo odio todas las #regionetiquetas , sino que apago el plegado de código en Visual Studio por completo. No me gusta el código que intenta esconderse de mí.
Daniel Pryden
2
"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". OTOH, encuentro que si divido una función en 3, a menudo encuentro más tarde que las partes individuales <i> son </i> útiles más tarde, por ejemplo. si algunos datos de entrada cambia sólo una fase, se puede comprobar que en el aislamiento, etc.
Jack V.

Respuestas:

65

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.

  1. No puede probar regiones, pero puede probar métodos verdaderos de forma aislada.
  2. Las regiones son comentarios, no elementos sintácticos. En el peor de los casos, la anidación de sus regiones y sus bloques se contradicen entre sí. Siempre debe esforzarse por representar la semántica de su estructura con los elementos sintácticos del lenguaje que está utilizando.
  3. Después de refactorizar los métodos, ya no es necesario doblar para leer el texto. Uno podría estar mirando el código fuente en cualquier herramienta que no tenga plegado, como un terminal, un cliente de correo, una vista web para su VCS o un visor de diferencias.
  4. Después de refactorizar los métodos, el método resultante es al menos tan bueno como con las regiones, además es más sencillo mover las partes individuales.
  5. El Principio de Responsabilidad Única sugiere que cualquier unidad debe tener una tarea y una sola tarea. La tarea del método "principal" es componer los métodos "auxiliares" para obtener el resultado deseado. Los métodos "auxiliares" resuelven un problema discreto y simple de forma aislada. La clase que contiene todos estos métodos también debe cumplir solo una tarea y solo debe contener los métodos relacionados con esa tarea. Por lo tanto, los métodos auxiliares pertenecen al ámbito de la clase, o el código no debería estar en la clase en primer lugar, sino al menos en algún método global o, mejor aún, debería inyectarse .

También relevante: pensamientos de Jeff Atwoods sobre el plegado de código

back2dos
fuente
99
1. La mayoría de los programadores no prueban todos los métodos privados. 2. El nombre de un método no puede transmitir todo lo que hay que saber sobre ese método; ¿Qué excepciones se pueden lanzar? ¿Es nulo una entrada válida? A veces está bien usar construcciones no sintácticas para hacer que su código sea más comprensible. En muchos idiomas, los archivos son un ejemplo de un elemento no sintáctico que es bastante aceptado como un medio para organizar el código. 3. Es mejor intentar sumergirse en el funcionamiento interno de un método en un IDE por una variedad de razones; Las situaciones en las que las regiones podrían morderlo en su VCS o cliente de correo son bastante raras.
jjoelson
3
4. Pero acaba de exportar cierta complejidad seria al resto de su clase. ¿Eso vale la pena? Además, las regiones se pueden mover tan fácilmente como una llamada a un método. 5. Ahora estás hablando de contaminar tu espacio de nombres con más clases que solo se usarán en un solo lugar. ¿Por qué las clases y los métodos son las únicas unidades de encapsulación que aceptará? Siempre puede crear esa nueva clase más tarde cuando (o si) se hace necesario tener esto separado.
jjoelson
77
@jjoelson: 1. ¿Y qué? 2. Exactamente mi punto: está bien usar construcciones no sintácticas si (y solo si) la sintaxis por sí sola no es suficiente. 3. "¿Raro?" - Supongo que tienes números para mostrar eso. Puedo decirle con certeza que la herramienta diff (o la culpa o lo que sea para el caso) incluida con TortoiseSVN no tiene plegado. 4. ¿Cómo se relaciona eso con el punto que hice? 5. Es por eso que la mayoría de los idiomas modernos tienen espacios de nombres anidables. Está recurriendo al arte ASCII en lugar de utilizar una amplia paleta de elementos de lenguaje disponibles para estructurar su código.
back2dos
44
@jjoelson: 1. Esa es su opinión y está fuera del alcance de esta pregunta. 2. Por extensión de mi argumento, las funciones anidadas son mejores que las regiones, sí. 3. Porque a veces necesito examinar varias revisiones para rastrear un problema. De cualquier manera, el código fuente está escrito para humanos, no para IDEs. 4. Por un lado, el argumento no está relacionado con mi punto, en segundo lugar, esa es una vez más su opinión, en tercer lugar, está fuera del alcance de esta pregunta. 5. C # tiene otros medios para estructurar el código además de la función de anidación. Debería usarlos o un lenguaje que permita funciones de anidamiento.
back2dos
13
Ustedes deberían tomar esto para conversar si aún desean debatir ... No me queda nada que valga la pena decirle al OP, es un desarrollador junior típico y obstinado basado en sus creencias. Nada cambiará de opinión, pero más experiencia en la OMI
maple_shaft
15

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.

"Primero obtiene las cosas, y luego las agita, luego, si necesitan un zumbido, lo hace, de lo contrario verifica si son azules e invierte su valor Copérnico. Luego, si la segunda cosa es mayor que la primera, nosotros necesita obtener la caja de jugo e insertarla ... "

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:

  • Comprensión más clara de lo que está sucediendo, incluso si solo se trata del nombre del método. Y estás equivocada de que un método no puede ser totalmente documentado - añadir el bloque de documentación (hit ///) y entrar en la descripción, parámetros, tipo de retorno, y también exception, example, remarksnodos al detalle esos escenarios. Ahí va, ¡para eso está!
  • No hay efectos secundarios ni problemas de alcance. Puede decir que declara todas sus variables en un sub-alcance con {}, pero ¿tengo que verificar todos los métodos para asegurarme de que no hizo 'trampa'? ¿Es esto lo dodgyObjectque 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).
  • Mi registro de eventos me dice en qué método se produjo una excepción. Sí, puedo encontrar el código ofensivo con un número de línea, pero conocer el nombre del método (especialmente si los he nombrado correctamente) me da una muy buena indicación de qué pasó y qué salió mal. "Oh, el TurnThingsUpsideDownmétodo falló, probablemente esté fallando al convertir una cosa mala" es mucho mejor que "Oh, el DoEverythingmé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.

Kirk Broadhurst
fuente
El análisis de comentarios XML de Visual Studio, junto con las etiquetas #region, se incluye en la categoría de características de Visual Studio. Mi punto es que no está mal confiar en estas características si todos en su proyecto están usando Visual Studio. En cuanto a los efectos secundarios y los problemas de alcance, aún puede arruinar las cosas con los campos globales. En cualquier caso, debe confiar en que los programadores no hagan cosas tontas con efectos secundarios.
jjoelson
55
@jjoelson Aún puede leer los comentarios XML sin Visual Studio, pero las etiquetas de región son casi completamente inútiles fuera de VS. La extensión lógica de su argumento es que un método gigante que ejecuta toda su aplicación está bien, ¡siempre que lo separe en regiones!
Kirk Broadhurst
2
@jjoelson, por favor, no nos hagas empezar a saber qué tan malos son los campos globales. Decir que algo no es útil porque tienes una "solución" para fastidiarlo de todos modos es una tontería. Simplemente mantenga sus métodos cortos y las variables con alcance.
OliverS
@OliverS, Kirk fue quien planteó el estado compartido como un problema con mi esquema de regiones en un método. Básicamente, estaba diciendo exactamente lo que está diciendo: el hecho de que un programador pueda abusar del estado al compartir demasiadas variables entre regiones no es una acusación de todo el esquema, al igual que la capacidad de arruinar el estado compartido entre los métodos a través de los globales no lo es. t una acusación del esquema de métodos múltiples.
jjoelson
7

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 #regiones 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 #regionque 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:

//
// ---------- COMPUTE SOMETHING OR OTHER ----------
//

Esto ayudará a alguien que navega por el código a ver las partes individuales de su método sin tener que lidiar con #regionetiquetas expandibles y colapsadas .

Kyralessa
fuente
2
¿Todo esto para un método que se llama en un solo lugar? Incluso la mayoría de los Lispers hardcore no abstraerán una función de orden superior hasta que hayan identificado al menos dos lugares donde se pueda usar para definir más fácilmente una función.
jjoelson
1
@jjoelson ¿Es tan difícil hacer una nueva clase? Qué es, una línea, una llave de apertura y una llave de cierre. Ah, y tienes que presionarctrl+n
Kirk Broadhurst
2
No es que sea difícil hacer una nueva clase, pero hay algunos gastos generales para tener una clase adicional. Es una capa más de indirección que hace que sea más difícil para un mantenedor de código encontrar lo que está buscando. No es que la gran cosa, pero también no le compra nada en el caso en que este fragmento de código es poco probable que se llama desde cualquier otro lugar. Y, como usted ha mencionado, es bastante fácil de hacer que la nueva clase y poner el código allí si resulta que haces necesidad de llamar a este fragmento de código en múltiples lugares.
jjoelson
2
@jjoelson, esta es una reacción bastante común. Fue mío, cuando supe por primera vez sobre cosas como SRP y DI, y fue la reacción de mis compañeros de trabajo cuando comenzamos a romper las dependencias. Si está viendo un caso individual , no parece que valga la pena. El beneficio está en el agregado. Una vez que comience a hacer SRP con todas sus clases, encontrará que es mucho más fácil cambiar una parte de su código sin que los cambios se extiendan por la mitad de su aplicación.
Kyralessa
@ Kyralessa, estos son métodos que solo se usan en un solo lugar. Cambiar dicho método no afectará a la mitad de su aplicación. Si dicho código se implementa como una región en el método que lo usa, entonces tiene una encapsulación perfecta; solo el método que contiene está usando el código, por lo que puede cambiarlo todo lo que quiera sin preocuparse por el efecto, excepto en ese método.
jjoelson
4

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.

árbol de arce
fuente
Las pruebas unitarias son ciertamente un punto justo, pero no estoy seguro de que justifique la contaminación del alcance de la clase en todos los casos. Hablando de manera realista, ¿alguien prueba realmente cada pequeño método privado que escribe? Yo diría que las personas tienden a probar los métodos privados que se utilizan mucho, es decir, métodos privados que serían candidatos para la reutilización de código de todos modos.
jjoelson
@jjoelson Si el método tiene una lógica significativa y no está envolviendo alguna otra funcionalidad, siempre escribo una prueba unitaria en su contra. Los métodos de prueba de la unidad no tienen nada que ver con la reutilización del código. Debe unir los métodos de prueba para verificar que para las entradas dadas obtenga las salidas esperadas de manera consistente y repetible. Si se da cuenta de que el alcance de la clase se está contaminando como lo llama, entonces tal vez su clase está violando el Principio de Responsabilidad Única.
maple_shaft
2
La mayoría de los programadores que he conocido no están de acuerdo con la idea de probar unitariamente cada método privado. Simplemente no vale la pena el tiempo que lleva implementar y mantener pruebas en todos los métodos privados.
jjoelson
3

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).

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.

Mason Wheeler
fuente
1
ctrl-f10- corre al cursor
Steven Jeuris
2

Mi 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:

  1. 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.

  2. 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.

PeterAllenWebb
fuente
2

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.

Steven Jeuris
fuente
Bueno, esencialmente uso regiones para delimitar párrafos de código (las regiones pueden tener comentarios que son visibles incluso cuando el código está plegado). Me gusta usar regiones para esto porque le da al encargado la opción de ver el código si quiere examinar la implementación o doblarlo si solo quiere ver el "panorama general".
jjoelson
1

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.

class Foo : IComparable
{
  private String name;
  private int foo;
  private Bar bar;

  public int CompareTo(Foo other)
  {
#region Ascending on name
     if (this.name < other.name) return -1;
     if (this.name > other.name) return 1;
#endregion
#region Usual order on bar
     int compBar = bar.compareTo(other.bar);
     if (compBar != 0) return compBar;
#endregion
#region Descending on foo
     if (this.foo > other.foo) return -1;
     if (this.foo < other.foo) return 1;
#endregion
     return 0; // equal
  }

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.

Sjoerd
fuente
0

No creo que haya una sola respuesta de por qué ciertas personas o equipos deciden no usarla, #regionpero si tuviera que enumerar algunas, estas serían las principales razones que he visto.

  • Los nombres y el orden de las regiones hacen más explícito el orden y la organización del código que impone un estilo particular que puede convertirse en una fuente de contención y motosierra.
  • La mayoría de los conceptos no encajan perfectamente en un pequeño número de regiones. Por lo general, comienza con las regiones por modificadores de acceso públicos , privados y luego por tipo de miembro (por ejemplo, método, propiedad, campo), pero luego, ¿qué pasa con los constructores que abarcan esos modificadores, variedades estáticas de todos estos, miembros protegidos, miembros internos, internos protegidos? miembros, miembros de la interfaz implícitos, eventos, etc. Al final, tendría las clases más bien diseñadas donde tiene un solo método o método en cada región debido a la categorización granular.
  • Si puede mantenerse pragmático y solo agrupar las cosas en tres o cuatro tipos de regiones consistentes, entonces eso puede funcionar, pero ¿qué valor realmente agrega? Si está diseñando bien las clases, realmente no debería necesitar examinar páginas de código.
  • Como se indicó anteriormente, las regiones pueden ocultar código feo que puede hacer que parezca menos problemático de lo que es. Mantenerlo como un dolor ocular puede ayudar a abordarlo.
jpierson
fuente