¿Cómo se puede evitar escribir código GUI hinchado?

48

Siempre que trabajo con código GUI, el código tiende a hincharse más rápido que otros tipos de código. También parece más difícil de refactorizar. Mientras que en otros tipos de código puedo refactorizar con bastante facilidad, encuentro que puedo descomponer una clase más grande en piezas más pequeñas de funcionalidad, con la mayoría de los marcos de GUI a menudo estoy vinculado a un marco que requiere mi widget / control / cualquier clase para implementar muchas más cosas más directamente en el widget / control / lo que sea. A veces esto se debe a la necesidad de (a) heredar de algún widget / control / cosa base o (b) necesitar acceso a métodos protegidos.

Por lo general, también tengo que, por ejemplo, responder a una gran variedad de entradas a través de señales / eventos / lo que sea del marco para implementar todos los modos de interacción con el usuario. Es posible que necesite en un control / widget GUI para manejar una gran variedad de entradas / salidas que pueden incluir:

  1. un clic derecho / menú contextual
  2. reaccionando a las selecciones del menú contextual, que pueden ser muchas
  3. una forma especial de pintar la GUI
  4. reaccionar a la entrada del teclado
  5. botones, casillas de verificación,
  6. etcétera etcétera

... todo el tiempo gestiona las clases bajo la GUI que representa la lógica empresarial.

Una GUI simple y directa puede hacer que su código crezca bastante rápido, incluso cuando separa la lógica de negocios y usa MVC, encuentro que el código GUI es un gran imán para el cambio.

¿Hay alguna forma de administrar el código GUI de una manera sensata y evitar que se convierta en una ventana rota? ¿O es una masa de controladores de eventos aleatorios / métodos anulados realmente lo mejor que podemos hacer para el código GUI?

Doug T.
fuente
44
¿Cuál es su definición exacta de "hinchazón"?

Respuestas:

36

Lo que hay que recordar sobre el código GUI es que está controlado por eventos, y el código controlado por eventos siempre tendrá la apariencia de una masa de controladores de eventos organizados al azar. Donde se vuelve realmente desordenado es cuando tratas de calzar el código no controlado por eventos en la clase. Claro, tiene la apariencia de proporcionar soporte para los controladores de eventos y puede mantener sus controladores de eventos agradables y pequeños, pero todo ese código de soporte adicional flotando hace que su fuente de GUI parezca hinchada y desordenada.

Entonces, ¿qué puede hacer al respecto y cómo puede hacer que las cosas sean más fáciles de refactorizar? Bueno, primero cambiaría mi definición de refactorización de algo que hago ocasionalmente a algo que hago continuamente mientras codifico. ¿Por qué? Porque desea refactorizar para permitirle modificar más fácilmente su código, y no al revés. No solo le pido que cambie la semántica aquí, sino que le pido que haga un poco de calistenia mental para ver su código de manera diferente.

Las tres técnicas de refactorización que considero que uso más comúnmente son Cambiar nombre , Método de extracción y Clase de extracción . Si nunca aprendí una sola refactorización, esas tres aún me permitirían mantener mi código limpio y bien estructurado, y por el contenido de su pregunta, me parece que probablemente se encontrará utilizando las mismas tres refactorizaciones casi constantemente en Para mantener su código GUI delgado y limpio.

Puede tener la mejor separación posible de GUI y lógica de negocios en el mundo, y aún así el código de GUI puede parecer una mina de código que se ha detonado en el medio. Mi consejo es que no está de más tener una o dos clases adicionales para ayudarlo a administrar su GUI correctamente, y esto no necesariamente tiene que ser sus clases de Vista si está aplicando el patrón MVC, aunque con frecuencia encontrará las clases intermedias son tan similares a su punto de vista que a menudo sentirá la necesidad de fusionarlas por conveniencia. Mi opinión sobre esto es que realmente no está de más agregar una capa adicional específica de GUI para administrar toda la lógica visual, sin embargo, es probable que desee sopesar los beneficios y los costos de hacerlo.

Mi consejo por lo tanto es:

  • No haga nada directamente detrás de su GUI excepto invocar y definir cómo la GUI se enganchará a la Vista (o una capa intermedia).
  • No trates de calzar cada cosa relacionada con la vista en una sola clase, o incluso en una sola clase por ventana GUI, a menos que tenga sentido que lo hagas. Su alternativa es crear muchas clases pequeñas y fáciles de administrar para administrar su lógica GUI.
  • Cuando sus métodos comiencen a verse un poco más grandes que 4-5 líneas de código, examine si esto es necesario y si es posible extraer uno o dos métodos para que pueda mantener sus métodos ajustados, incluso si esto significa una clase Con muchos más métodos.
  • Si sus clases comienzan a verse realmente grandes, comience eliminando TODAS las funcionalidades duplicadas y luego vea si puede agrupar lógicamente sus métodos para poder extraer otra clase o dos.
  • Piense en refactorizar cada vez que escriba una línea de código. Si consigue que funcione una línea de código, vea si puede refactorizarla para evitar la duplicación de funciones o para que sea un poco más ágil sin cambiar el comportamiento.
  • Acepte lo inevitable, que siempre sentirá que una parte u otra en su sistema comenzará a sentirse un poco hinchada, especialmente si descuida la refactorización a medida que avanza. Incluso con una base de código bien factorizada, aún puede sentir que hay más que puede hacer. Esta es la realidad del software de escritura: siempre se sentirá que algo más se podría haber hecho "mejor", por lo que debe lograr un equilibrio entre hacer un trabajo profesional y el enchapado en oro.
  • Acepte que cuanto más limpio intente mantener su código, menos hinchado parecerá su código.
S.Robins
fuente
3
+1 Nos guste o no, una GUI se encarga de un trillón de operaciones detalladas y eso significa código.
Patrick Hughes
Los desarrolladores deben aprender a usar la codificación controlada por eventos para la GUI.
David Gao
23

Creo que muchos de los problemas que está experimentando se remontan a una causa simple. La mayoría de los desarrolladores no tratan el código GUI como un código 'real'. No tengo evidencia o estadísticas aquí, solo mi instinto.

Tal vez piensan que es ' solo presentación ' y no importante. " No hay lógica de negocios allí ", dicen, " ¿ por qué la unidad lo prueba "? Se ríen cuando mencionas la orientación a objetos y escribes código limpio. Ni siquiera INTENTAN mejorar las cosas. Para empezar, no hay una estructura, solo dan un poco de código y lo dejan pudrirse a medida que otros agregan su propio toque con el tiempo. Un hermoso desastre, código de graffiti.

El código GUI tiene sus desafíos únicos, por lo tanto, debe tratarse de manera diferente y con respeto. Necesita amor y desarrolladores que quieran escribirlo. Los que lo mantendrán delgado y le darán una buena estructura y patrones correctos.

c_maker
fuente
2
+1 por aludir a la percepción de que el código GUI se trata de manera diferente al código que no es GUI. Perdí la cuenta de la cantidad de veces que escuché a alguien decir: "no te molestes en probar la GUI porque no es rentable y además es muy difícil de hacer". Usualmente traduzco a "¡Es difícil y soy demasiado vago para aprender cómo hacerlo!".
S.Robins
1
+1 Donde trabajo a menudo no revisamos el código GUI: "es solo GUI, omítelo". Y soy tan culpable como cualquiera. Lo extraño es que en mis proyectos personales paso mucho tiempo tratando de obtener un código GUI limpio y agradable. Supongo que es solo una cuestión de cultura.
HappyCat
8

Por alguna razón, el código GUI crea un punto ciego en los desarrolladores sobre la separación de preocupaciones. Tal vez sea porque todos los tutoriales agrupan todo en una clase. Tal vez sea porque la representación física hace que las cosas parezcan más estrechamente acopladas de lo que son. Tal vez sea porque las clases se desarrollan lentamente para que las personas no reconozcan que necesitan una refactorización, como la proverbial rana que se hierve al aumentar lentamente el calor.

Cualquiera sea la razón, la solución es hacer que sus clases sean mucho más pequeñas. Hago esto preguntándome continuamente si es posible poner lo que estoy escribiendo en una clase separada. Si es posible ingresar a otra clase, y puedo pensar en un nombre razonable y simple para esa clase, entonces lo hago.

Karl Bielefeldt
fuente
6

Es posible que desee echar un vistazo al modelo Presentador de vista de modelo / Vista pasiva. Ray Ryan dio una buena charla en un Google IO sobre las mejores prácticas de arquitectura para GWT.

http://www.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html

Es fácil abstraer las ideas a otros marcos e idiomas. El principal beneficio de MVP (en mi opinión) es la capacidad de prueba unitaria. Y solo obtienes eso, si tu código no está hinchado y no es espagueti (a juzgar por tu pregunta, esto es lo que quieres). Funciona al introducir una capa de lógica de vista llamada presentador. La vista real se desacopla de esto a través de una interfaz (y, por lo tanto, se puede burlar fácilmente en pruebas unitarias). Ahora, dado que su capa de lógica de vista (el presentador) está libre de los elementos internos del marco de GUI concreto, puede organizarlo como un código normal y no está vinculado, por ejemplo, a la jerarquía de herencia de Swings. Idealmente, podría cambiar las implementaciones de GUI en diferentes marcos, siempre que se ajusten a la misma interfaz.

Scarfridge
fuente
1
+1. MVP se centra exactamente en cómo extraer la lógica de la GUI en clases separadas, que a menudo es bastante diferente de lo que las personas entienden cuando hablan de MVC.
Doc Brown
5

Mi respuesta consta de cuatro partes: estructura, simplicidad, pruebas y sintaxis.

¡Los tres primeros son realmente difíciles de hacer!

Estructura significa prestar mucha atención al uso de la menor cantidad de código y la cantidad máxima de marcos, bibliotecas, etc.

La simplicidad significa mantener las cosas simples desde el diseño inicial hasta la implementación real. Mantener la navegación simple, usar complementos simples, mantener el diseño bastante 'simple', todo ayudará aquí. Ahora se pueden 'vender' a clientes / usuarios que pueden ver rápidamente las ventajas de las páginas que funcionan en computadoras, ipad, dispositivos móviles y otros dispositivos.

Probar significa incluir herramientas de prueba de navegador (me vienen a la mente webrat y carpincho con mi trabajo en rieles) que detectan problemas cruzados en el navegador por adelantado cuando se puede diseñar un mejor código para tratarlos al principio en lugar de los frecuentes 'parches' de código por diferentes desarrolladores ya que son 'descubiertos' por usuarios de diferentes navegadores.

Sintaxis. Es realmente útil usar un corrector de código / IDE / plugin de editor, etc. para su HTML, CSS, Javascript, etc. La ventaja que han obtenido los navegadores al manejar HTML mal formado funciona en su contra cuando los diferentes navegadores funcionan de manera diferente con así que es esencial una herramienta que verifique su formato HTML. Tener HTML bien formado es muy útil para tener HTML no bloqueado ya que un código incorrecto debería tener más visibilidad.

Michael Durrant
fuente
4

La solución que he encontrado es el código declarativo. El uso de solo código de procedimiento es una receta para el código GUI de espagueti. Claro, una "forma especial de pintar el widget" probablemente seguirá siendo el código. Pero este es un código aislado en una clase. Controladores de eventos, métodos abreviados de teclado, tamaños de ventana: todo lo que es desordenado se declara mejor.

MSalters
fuente
4

Hay muchas respuestas geniales aquí.

Una cosa que me ha ayudado a simplificar el código GUI es asegurarme de que la GUI tenga su propio modelo de datos.

Para tomar un ejemplo simple, si tengo una GUI con 4 campos de entrada de texto, entonces tengo una clase de datos separada que mantiene el contenido de esos 4 campos de entrada de texto. Las GUI más complicadas requieren más clases de datos.

Diseño una GUI como modelo - vista. El modelo de GUI es controlado por el controlador de la aplicación del modelo de aplicación - vista - controlador. La vista de la aplicación es el modelo GUI, en lugar del código GUI en sí.

Gilbert Le Blanc
fuente
2

Las aplicaciones como procesamiento de textos, editores gráficos, etc. tienen interfaces complejas y su código no puede ser simple. Sin embargo, para las aplicaciones comerciales, la GUI no tiene que ser tan compleja, sino más o menos como es.

Algunas de las claves para simplificar la GUI son (la mayoría se aplican a .NET):

  1. Esfuércese por un diseño más simple siempre que sea posible. Evite comportamientos sofisticados si la empresa no lo solicita.

  2. Use un buen proveedor de controles.

  3. No cree la funcionalidad de control personalizado en el código del cliente en sí. En su lugar, cree controles de usuario que extiendan el control original de tal manera que pueda reflejar sus comportamientos específicos en los controles en lugar de en el código del formulario / página en uso.

  4. Use un marco de trabajo (incluso un producto propio) para manejar la internacionalización, la administración de recursos, los estilos, etc. para que no repita este código en cada interfaz de usuario.

  5. Emplear un componente (o marco) para la navegación.

  6. Cree diálogos estándar para errores, advertencias, confirmación, etc.

Ninguna posibilidad
fuente
1

Aplique el diseño orientado a objetos a su código y para el desarrollo de la interfaz de usuario:

  1. Presentación y modelo separados Utilice una biblioteca / marco de MV-lo que sea, o escriba el suyo propio, para ayudar a separar la lógica de vista / controlador del modelo de datos. Toda comunicación con el backend debe realizarse dentro del modelo, y el estado del modelo siempre debe estar sincronizado con el backend.
  2. Desacoplamiento Si el objeto A sabe acerca del objeto B, entonces A puede invocar métodos en B, pero B no debe saber acerca de A. En cambio, A puede escuchar los eventos de B. Se asegura de que no haya dependencia circular. Si su aplicación tiene muchos eventos entre componentes, cree un EventBus o aproveche un marco basado en eventos como Twitter Flight.
  3. Representación parcial frente a completa Si su vista es una tabla o lista de elementos, puede verse tentado a crear métodos como "agregar", "eliminar" para insertar / eliminar un elemento en / de la colección. Su código podría hincharse fácilmente cuando tiene que admitir la clasificación y la paginación. Entonces, mi consejo es: simplemente vuelva a representar toda la vista incluso cuando haya un cambio parcial. ¿Qué pasa con el rendimiento? bueno, si tu colección es grande, entonces debes hacer paginación de todos modos. Desarrollador web: asegúrese de que sus controladores de eventos estén delegados en el elemento raíz de la vista que no cambia.
  4. Modelo de vista Cuando el estado de su vista se vuelve demasiado complicado de mantener, por ejemplo, una vista de tabla debe realizar un seguimiento de los datos de fila, datos de columna, orden de clasificación, filas actualmente verificadas (si admite verificación múltiple), etc., probablemente debería crear un objeto ViewModel para esos estados. Su objeto View debería llamar a los setters en ViewModel si algo cambia en la IU (por ejemplo: el usuario verifica una fila); y debería responder al evento de cambio de ViewModel actualizando la IU. Por lo general, debe evitar actualizar la interfaz de usuario si el evento de cambio se desencadena por la interfaz de usuario.

Aquí hay una aplicación pequeña pero no trivial para ayudar a ilustrar algunos de mis puntos. Puede encontrar el código y ver el diagrama de interacción del modelo aquí: https://github.com/vanfrankie/pushpopbox

franco
fuente
0

Desea echar un vistazo al concepto de "enlace de datos" . Esta es una forma de conectar elementos de la IU a elementos del modelo abstracto de manera declarativa, de modo que los elementos del modelo se sincronicen automáticamente con el contenido de la IU. Hay muchos beneficios de este enfoque, por ejemplo, no tener que escribir los controladores de eventos usted mismo para sincronizar los datos.

Hay soporte de enlace de datos para muchos marcos de UI, por ejemplo .NET y Eclipse / JFace .

JesperE
fuente