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

46

Encuentro que cuando trabajo con el código GUI, el código tiende a inflarse más rápido que otros tipos de código. También parece más difícil refactorizar. Mientras que en otros tipos de código puedo refactorizar con bastante facilidad (me parece 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 / thing básico o (b) necesita acceso a métodos protegidos.

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

  1. un clic derecho / menú contextual
  2. reaccionar 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 etc

... administre todo el tiempo las clases bajo la GUI que representa la lógica de negocios.

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

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

    
pregunta Doug T. 17.04.2012 - 02:31

10 respuestas

36

Lo que hay que recordar acerca del código GUI es que es impulsado por eventos, y el código impulsado por eventos siempre tendrá la apariencia de una masa de manejadores de eventos organizados al azar. Donde realmente se ensucia es cuando intentas meter en la clase código no impulsado por eventos. Claro, tiene la apariencia de proporcionar soporte para los manejadores de eventos y puedes mantener tus manejadores de eventos agradables y pequeños, pero todo ese código de soporte adicional que flota alrededor hace que tu fuente de GUI parezca inflada y sucia.

Entonces, ¿qué puedes hacer al respecto y cómo puedes hacer las cosas más fáciles de refactorizar? Bueno, primero cambiaría mi definición de refactorización de algo que hago en ocasiones a algo que hago continuamente mientras código. ¿Por qué? Porque desea que la refactorización le permita modificar su código más fácilmente, y no al revés. No te estoy pidiendo simplemente que cambies la semántica aquí, sino que te pido que hagas un poco de calistenia mental para ver tu código de manera diferente.

Las tres técnicas de refactorización que utilizo con mayor frecuencia son Cambiar nombre , Método de extracción y Clase de extracción . Si nunca aprendiera una sola otra refactorización, esos 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á usando 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 la GUI puede parecer que un código mío ha sido detonado en medio de él. Mi consejo es que no está de más tener una clase extra o dos para ayudarlo a administrar su GUI correctamente, y esto no necesariamente tiene que ser su clase de Ver si está aplicando el patrón MVC - aunque con frecuencia encontrará que las clases intermedias son tan similares a su opinión que a menudo sentirá la necesidad de combinarlas por conveniencia. Mi opinión sobre esto es que realmente no está mal 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.

Por lo tanto, mi consejo es:

  • No haga nada directamente detrás de su GUI, excepto para invocar y definir cómo se conectará la GUI en la Vista (o una capa intermedia).
  • No intente calmar 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 haga. Su alternativa es crear muchas clases pequeñas y fáciles de administrar para administrar su lógica GUI.
  • Cuando sus métodos comienzan a parecer un poco más grandes que un código de 4-5 líneas, examine si esto es necesario y si es posible extraer uno o dos métodos para que pueda mantener sus métodos magros, incluso si esto significa una clase con muchos más métodos.
  • Si sus clases comienzan a parecer muy grandes, comience por eliminar TODA la funcionalidad duplicada y luego vea si puede agrupar sus métodos de manera lógica para poder extraer otra clase o dos.
  • Piense en la refactorización cada vez que escriba una línea de código. Si obtiene una línea de código para trabajar, vea si puede refactorizarla para evitar la duplicación de la funcionalidad, o para hacerla un poco más sencilla 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, puedes sentir que hay más de lo que podrías hacer. Esta es la realidad de escribir software, ya que siempre tendrá la sensación de que algo más podría haberse hecho "mejor", por lo que debe encontrar un equilibrio entre hacer un trabajo profesional y chapado en oro.
  • Acepte que cuanto más limpia intente y guarde su código, menor será su código.
respondido por el S.Robins 17.04.2012 - 04:54
22

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

Tal vez piensen que es ' solo presentación ' y no es 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 hacer las cosas mejor. No hay una estructura para comenzar, solo dan una palmada a un código y lo dejan pudrirse a medida que otros agregan su propio toque con el tiempo. Un hermoso lío, código de graffiti.

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

    
respondido por el c_maker 17.04.2012 - 03:29
7

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 unidas que lo que son. Tal vez es porque las clases se construyen lentamente para que las personas no reconozcan que necesitan refactorizar, como la rana proverbial 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 poner en otra clase, y puedo pensar en un nombre razonable y simple para esa clase, entonces lo hago.

    
respondido por el Karl Bielefeldt 17.04.2012 - 19:45
5

Es posible que desee echar un vistazo al patrón del Visor de modelos / Vista pasiva. Ray Ryan dio una buena charla en un Google IO sobre las mejores prácticas de arquitectura para GWT.

enlace

Es fácil abstraer las ideas de otros marcos e idiomas. El principal beneficio de MVP (en mi opinión) es la capacidad de prueba de la unidad. Y solo obtendrás eso, si tu código no está abultado ni espagueti (a juzgar por tu pregunta, esto es lo que quieres). Funciona introduciendo una capa de lógica de vista denominada presentador. La vista real se desacopla de esto a través de una interfaz (y, por lo tanto, se puede burlar fácilmente en las pruebas unitarias). Ahora, ya que su capa de lógica de vista (el presentador) se libera de los elementos internos del marco de la GUI concreta, puede organizarlo como código normal y no está vinculado a, por ejemplo, Columpios de jerarquía hereditaria. Lo ideal sería cambiar las implementaciones de la GUI en diferentes marcos, siempre y cuando se ajusten a la misma interfaz.

    
respondido por el scarfridge 17.04.2012 - 12:29
5

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

¡Los tres primeros son muy 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.

Simplicidad significa mantener las cosas simples desde el diseño inicial hasta la implementación real. Manteniendo la navegación simple, utilizando complementos simples, manteniendo el diseño bastante 'simple', todo esto ayudará. Ahora pueden 'venderse' a clientes / usuarios que pueden ver rápidamente las ventajas de las páginas que funcionan en computadoras, ipad, dispositivos móviles y otros.

Pruebas significa que incluye herramientas de prueba del navegador (webrat y capybara vienen a mi mente con el trabajo de mis rieles) que detectan los problemas de los navegadores cruzados cuando se puede diseñar un mejor código para tratarlos al principio a diferencia del frecuente "parcheo" del código por parte de diferentes desarrolladores, ya que son "descubiertos" por usuarios de diferentes navegadores.

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

    
respondido por el Michael Durrant 17.04.2012 - 03:00
4

La solución que he encontrado es un código declarativo. Usar solo el código de procedimiento es una receta para el código GUI de los espaguetis. 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 ventanas: todo lo que se ensucia se declara mejor.

    
respondido por el MSalters 17.04.2012 - 14:12
4

Hay muchas respuestas geniales aquí.

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

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

Diseño una GUI como vista de modelo. El modelo GUI está 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 propio código GUI.

    
respondido por el Gilbert Le Blanc 18.04.2012 - 15:41
2

Las aplicaciones como Procesador de textos, editores de gráficos, etc. tienen interfaces complejas y su código no puede ser simple. Sin embargo, para las aplicaciones de negocios, la GUI no tiene que ser tan compleja, pero en cierta forma sigue siendo así.

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

  1. Luche por un diseño más simple siempre que sea posible. Evite comportamientos extravagantes si no es requerido por la empresa.

  2. Use un buen proveedor de controles.

  3. No cree una funcionalidad de control personalizada en el propio código del cliente. 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 de uso.

  4. Use un marco (incluso uno propio) para manejar la internacionalización, la gestión de recursos, los estilos, etc., de modo que no repita este código en cada IU.

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

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

respondido por el NoChance 17.04.2012 - 04:45
1

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

  1. Presentación y modelo separados Use un MV / cualquier biblioteca / marco, o escriba el suyo, para ayudar a separar la lógica de la vista / controlador del modelo de datos. Toda la 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 sobre el objeto B, A puede llamar a los métodos en B, pero B no debería saber acerca de A. En su lugar, 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 tener la tentación de 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. Así que mi consejo es: simplemente vuelva a representar la vista completa incluso cuando haya un cambio parcial. ¿Qué pasa con el rendimiento? Bueno, si tu colección es grande, entonces deberías hacer paginación de todos modos. Desarrollador web: asegúrese de que sus controladores de eventos estén delegados al 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 hacer un seguimiento de los datos de las filas, los datos de las columnas, el orden de clasificación y las filas actualmente verificadas ), etc., probablemente debería crear un objeto ViewModel para esos estados. Su objeto View debería llamar a los configuradores en ViewModel si algo cambia en la interfaz de usuario (por ejemplo: el usuario verifica una fila); y debe responder al evento de cambio de ViewModel actualizando la interfaz de usuario. 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í: enlace

    
respondido por el frank 04.03.2013 - 00:27
0

Desea echar un vistazo al concepto de "enlace de datos" . Esta es una manera de conectar los elementos de la interfaz de usuario a los elementos abstractos del modelo de manera declarativa, de modo que los elementos del modelo se sincronizan automáticamente con el contenido de la interfaz de usuario. 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 .

    
respondido por el JesperE 04.03.2013 - 08:20

Lea otras preguntas en las etiquetas