Como alguém pode evitar escrever código GUI inchado?

48

Acho que sempre que trabalho com código da GUI, o código tende a inchar mais rapidamente que outros tipos de código. Também parece mais difícil de refatorar. Enquanto em outros tipos de código eu posso refatorar com bastante facilidade - acho que posso decompor uma classe maior em partes menores de funcionalidade - com a maioria das estruturas de GUI, muitas vezes estou vinculado a uma estrutura que requer meu widget / controle / qualquer classe implementar muito mais coisas diretamente no widget / controle / qualquer coisa. Às vezes, isso se deve à necessidade de (a) herdar algum widget / controle / coisa base ou (b) precisar de acesso a métodos protegidos.

Normalmente, também tenho que, por exemplo, responder a uma grande variedade de entradas via sinais / eventos / o que for da estrutura para implementar todos os modos de interação com o usuário. Talvez eu precise de um widget / controle da GUI para lidar com uma grande variedade de entradas / saídas que podem incluir:

  1. um clique direito / menu de contexto
  2. reagindo às seleções do menu de contexto - que podem ser muitas
  3. uma maneira especial de pintar a GUI
  4. reagir à entrada do teclado
  5. botões, caixas de seleção,
  6. etc etc

... gerencia o tempo todo as classes sob a GUI que representa a lógica de negócios.

Uma GUI simples e direta pode fazer com que seu código cresça rapidamente, mesmo ao separar a lógica de negócios e ao usar o MVC, acho que o código da GUI é um grande ímã para a mudança.

Existe alguma maneira de gerenciar o código da GUI de maneira sã e evitar que ele se torne uma janela quebrada? Ou é uma massa de manipuladores de eventos aleatórios / métodos substituídos realmente o melhor que podemos fazer para o código da GUI?

Doug T.
fonte
4
Qual é a sua definição exata de "inchaço"?

Respostas:

36

O que deve ser lembrado sobre o código da GUI é que ele é orientado a eventos, e o código orientado a eventos sempre terá a aparência de uma massa de manipuladores de eventos organizados aleatoriamente. O que fica realmente confuso é quando você tenta inserir código não orientado a eventos na classe. Claro, ele tem a aparência de fornecer suporte para os manipuladores de eventos e você pode manter seus manipuladores de eventos agradáveis ​​e pequenos, mas todo esse código de suporte extra flutuando faz com que a fonte da GUI pareça inchada e confusa.

Então, o que você pode fazer sobre isso e como facilitar a refatoração das coisas? Bem, eu mudaria primeiro minha definição de refatoração de algo que faço ocasionalmente para algo que faço continuamente enquanto codifico. Por quê? Porque você deseja que a refatoração permita modificar mais facilmente seu código, e não o contrário. Não estou simplesmente pedindo para você alterar a semântica aqui, mas pedindo para fazer um pouco de ginástica mental para ver seu código de maneira diferente.

As três técnicas de refatoração que considero mais comuns são Renomear , Extrair Método e Extrair Classe . Se eu nunca aprendi uma única refatoração, essas três ainda me permitiriam manter meu código limpo e bem estruturado, e pelo conteúdo de sua pergunta, parece-me que você provavelmente se encontrará usando as mesmas três refatorações quase constantemente para manter seu código GUI fino e limpo.

Você pode ter a melhor separação possível da GUI e da lógica de negócios do mundo, e ainda assim o código da GUI pode parecer um código que a minha foi detonada no meio dela. Meu conselho é que não custa ter uma classe extra ou duas para ajudá-lo a gerenciar sua GUI corretamente, e isso não necessariamente precisa ser a sua classe View se você estiver aplicando o padrão MVC - embora frequentemente você encontre as classes intermediárias são tão parecidas com a sua visão que você geralmente sente vontade de mesclá-las por conveniência. Minha opinião é que não é realmente necessário adicionar uma camada específica específica da GUI para gerenciar toda a lógica visual; no entanto, você provavelmente deseja avaliar os benefícios e custos de fazê-lo.

Portanto, meu conselho é:

  • Não faça nada diretamente atrás da sua GUI, exceto para chamar e definir como a GUI será conectada à Visualização (ou a uma camada intermediária).
  • Não tente usar todas as coisas relacionadas à exibição em uma única classe - ou mesmo uma única classe por janela da GUI - a menos que faça sentido fazer isso. Sua alternativa é criar muitas classes pequenas e fáceis de gerenciar para gerenciar sua lógica da GUI.
  • Quando seus métodos começarem a parecer um pouco maiores que 4-5 linhas de código, examine se isso é necessário e se é possível extrair um ou dois métodos para que você possa manter seus métodos enxutos, mesmo que isso signifique uma classe com muito mais métodos.
  • Se suas classes estão começando a parecer realmente grandes, comece removendo TODAS as funcionalidades duplicadas e verifique se você pode agrupar logicamente seus métodos para extrair outra ou duas classes.
  • Pense em refatorar toda vez que escrever uma linha de código. Se você conseguir que uma linha de código funcione, verifique se é possível refatorá-la para evitar duplicar a funcionalidade ou torná-la um pouco mais enxuta sem alterar o comportamento.
  • Aceite o inevitável: você sempre sentirá que uma parte ou outra do seu sistema começará a ficar um pouco inchada, especialmente se você negligenciar a refatoração à medida que avança. Mesmo com uma base de código bem fatorada, você ainda pode sentir que há mais que poderia fazer. Essa é a realidade do software de escrita, que você sempre sentirá que algo mais poderia ter sido feito "melhor"; portanto, é necessário encontrar um equilíbrio entre realizar um trabalho profissional e investir em ouro.
  • Aceite que, quanto mais limpo você tentar manter seu código, menos inchado ele parecerá.
S.Robins
fonte
3
+1 Goste ou não, uma GUI cuida de um zilhão de operações detalhadas e isso significa código.
22712 Patrick Hughes
Os desenvolvedores devem aprender a usar a codificação orientada a eventos para a GUI.
David Gao
23

Eu acho que muitos dos problemas que você está enfrentando podem ser rastreados até uma causa simples. A maioria dos desenvolvedores não trata o código da GUI como código 'real'. Não tenho evidências ou estatísticas aqui, apenas meu pressentimento.

Talvez eles pensem que é apenas uma apresentação e não é importante. ' Não há lógica de negócios lá ', eles dizem, ' por que testá-lo por unidade '? Eles riem quando você menciona orientação a objetos e escreve código limpo. Eles nem tentam melhorar as coisas. Para começar, não existe uma estrutura, eles simplesmente digitam algum código e o deixam apodrecer, enquanto outros adicionam seu próprio toque ao longo do tempo. Uma bagunça linda, código de graffiti.

O código da GUI tem seus desafios únicos, portanto, deve ser tratado de maneira diferente e com respeito. Precisa de amor e desenvolvedores que queiram escrever. Os que o manterão fino e darão uma boa estrutura e padrões corretos.

c_maker
fonte
2
+1 por fazer alusão à percepção de que o código da GUI está sendo tratado de maneira diferente do código não-GUI. Eu perdi a conta do número de vezes que ouvi alguém dizer: "não se preocupe em testar a GUI porque ela não é rentável e, além disso, é muito difícil de executar". Eu costumo traduzir para "É difícil e tenho preguiça de aprender como fazer isso!".
S.Robins
1
+1 Onde trabalho, geralmente não analisamos o código da GUI - "é apenas GUI, pule". E eu sou tão culpado quanto qualquer um. O estranho é que, em meus projetos pessoais, passo muito tempo tentando obter um bom código limpo da GUI. Acho que é apenas uma coisa cultural.
21912 HappyCat
8

Por alguma razão, o código da GUI cria um ponto cego nos desenvolvedores sobre a separação de preocupações. Talvez seja porque todos os tutoriais agrupam tudo em uma classe. Talvez seja porque a representação física faz as coisas parecerem mais intimamente ligadas do que são. Talvez seja porque as aulas são construídas lentamente, para que as pessoas não reconheçam que precisam de refatoração, como o sapo proverbial sendo fervido lentamente aumentando o calor.

Seja qual for o motivo, a solução é tornar suas aulas muito menores. Eu faço isso perguntando-me continuamente se é possível colocar o que estou digitando em uma classe separada. Se é possível colocar em outra classe, e eu consigo pensar em um nome razoável e simples para essa classe, eu faço.

Karl Bielefeldt
fonte
6

Você pode dar uma olhada no padrão Model View Presenter / Passive View. Ray Ryan fez uma boa palestra em um IO do Google sobre as melhores práticas de arquitetura para o GWT.

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

É fácil abstrair as idéias para outras estruturas e linguagens. O principal benefício do MVP (na minha opinião) é a testabilidade unitária. E você só consegue isso, se o seu código não estiver inchado e nem espaguete (a julgar pela sua pergunta, é isso que você deseja). Ele funciona introduzindo uma camada lógica de exibição chamada apresentador. A visão real é dissociada disso por meio de uma interface (e, portanto, pode ser facilmente zombada em testes de unidade). Agora, como sua camada lógica de exibição (o apresentador) é liberada das partes internas da estrutura da GUI concreta, você pode organizá-la como um código regular e não está ligada a, por exemplo, a hierarquia de herança Swings. Idealmente, você pode alternar as implementações da GUI em diferentes estruturas, desde que estejam em conformidade com a mesma interface.

scarfridge
fonte
1
+1. O MVP se concentra exatamente em como extrair a lógica da GUI em classes separadas, o que geralmente é bem diferente do que as pessoas entendem quando falam em MVC.
Doc Brown
5

Minha resposta consiste em quatro partes: estrutura, simplicidade, teste e sintaxe.

Os três primeiros são realmente difíceis de fazer!

Estrutura significa prestar muita atenção ao uso da menor quantidade de código e do máximo de estruturas, bibliotecas etc.

Simplicidade significa manter as coisas simples, desde o design inicial até a implementação real. Manter a navegação simples, usar plugins simples, manter o layout razoavelmente "claro" ajudará aqui. Agora eles podem ser "vendidos" para clientes / usuários que podem ver rapidamente as vantagens de páginas que funcionam em computadores, ipad, dispositivos móveis e outros.

Testar significa incluir ferramentas de teste de navegador (webrat e capivara vêm à mente com o meu trabalho de trilhos) que capturam problemas entre navegadores desde o início, quando um código melhor pode ser projetado para lidar com eles no início, em oposição aos frequentes 'patches' de código por diferentes desenvolvedores, pois são 'descobertos' por usuários de diferentes navegadores.

Sintaxe. É realmente útil usar um verificador de código / IDE / plugin de editor, etc. para seu HTML, CSS, Javascript etc. A vantagem que os navegadores obtiveram ao lidar com HTML malformado funciona contra você quando diferentes navegadores têm um desempenho diferente. portanto, é essencial uma ferramenta que verifique seu formato HTML. Ter HTML bem formado é muito útil para ter HTML não vazio porque o código incorreto deve ter mais visibilidade.

Michael Durrant
fonte
4

A solução que encontrei é o código declarativo. Usar apenas código processual é uma receita para o código da GUI de espaguete. Certamente, uma "maneira especial de pintar o widget" provavelmente continuará sendo o código. Mas esse é um código isolado em uma classe. Manipuladores de eventos, atalhos de teclado, tamanhos de janelas - todas essas coisas bagunçadas são melhor declaradas.

MSalters
fonte
4

Há muitas ótimas respostas aqui.

Uma coisa que me ajudou a simplificar o código da GUI é garantir que a GUI tenha seu próprio modelo de dados.

Para dar um exemplo simples, se eu tenho uma GUI com 4 campos de entrada de texto, tenho uma classe de dados separada que mantém o conteúdo desses 4 campos de entrada de texto. GUIs mais complicadas exigem mais classes de dados.

Eu desenho uma GUI como modelo - visão. O modelo da GUI é controlado pelo controlador de aplicativo do modelo de aplicativo - visualização - controlador. A visualização do aplicativo é o modelo da GUI, em vez do próprio código da GUI.

Gilbert Le Blanc
fonte
2

Aplicativos como processamento de texto, editores gráficos etc. têm interfaces complexas e seu código não pode ser simples. No entanto, para aplicativos de negócios, a GUI não precisa ser tão complexa, mas de alguma forma ainda é.

Algumas das chaves para simplificar a GUI são (a maioria se aplica ao .NET):

  1. Busque um design mais simples sempre que possível. Evite comportamentos extravagantes se não for solicitado pela empresa.

  2. Use um bom provedor de controles.

  3. Não crie funcionalidade de controle personalizado no próprio código do cliente. Em vez disso, crie controles de usuário que estendam o controle original de maneira que você possa refletir seus comportamentos específicos nos controles, e não no código do formulário / página em uso.

  4. Use uma estrutura (mesmo doméstica) para lidar com internacionalização, gerenciamento de recursos, estilos etc. para não repetir esse código em todas as UI.

  5. Empregue um componente (ou estrutura) para navegação.

  6. Crie diálogos padrão para erros, avisos, confirmação etc.

NoChance
fonte
1

Aplique o Design Orientado a Objetos ao seu código e para o desenvolvimento da UI:

  1. Apresentação e modelo separados Use uma biblioteca / estrutura de MV, qualquer que seja, ou escreva sua própria, para ajudar a separar a lógica da visualização / controlador do modelo de dados. Toda a comunicação com o back-end deve ser feita dentro do modelo, e o estado do modelo deve sempre estar sincronizado com o back-end.
  2. Desacoplando Se o objeto A conhece o objeto B, A pode chamar métodos em B, mas B não deve saber sobre A. Em vez disso, A pode escutar eventos de B. Ele garante que não haja dependência circular. Se seu aplicativo tiver muitos eventos entre componentes, crie um EventBus ou utilize uma estrutura orientada a eventos como o Twitter Flight.
  3. Renderização parcial versus renderização total Se sua visualização for uma tabela ou lista de itens, você poderá criar métodos como "adicionar", "remover" para inserir / excluir um item na / da coleção. Seu código pode inchar facilmente quando você precisa oferecer suporte à classificação e paginação. Portanto, meu conselho é: simplesmente renderize novamente toda a exibição, mesmo quando houver uma alteração parcial. E o desempenho? bem, se sua coleção é grande, você deve fazer a paginação de qualquer maneira. Desenvolvedor da Web: verifique se os manipuladores de eventos estão delegados ao elemento raiz da exibição, que não muda.
  4. Modelo de visualização Quando o estado da sua visualização se torna muito complicado para manter, por exemplo, uma visualização de tabela deve acompanhar os dados da linha, dados da coluna, ordem de classificação, linhas atualmente verificadas (se ela suporta a verificação múltipla), etc, você provavelmente crie um objeto ViewModel para esses estados. Seu objeto View deve chamar setters no ViewModel se algo mudar na interface do usuário (por exemplo: o usuário verifica uma linha); e deve responder ao evento de alteração do ViewModel atualizando a interface do usuário. Geralmente, você deve evitar atualizar a interface do usuário se o evento de alteração for acionado pela interface do usuário.

Aqui está um aplicativo pequeno, mas não trivial, para ajudar a ilustrar alguns dos meus pontos. Você pode encontrar o código e visualizar o diagrama de interação do modelo aqui: https://github.com/vanfrankie/pushpopbox

sincero
fonte
0

Você quer dar uma olhada no conceito de "ligação de dados" . É uma maneira de conectar elementos da interface do usuário a elementos abstratos do modelo de maneira declarativa, de forma que os elementos do modelo sejam sincronizados automaticamente com o conteúdo da interface do usuário. Há muitos benefícios dessa abordagem, por exemplo, não ter que escrever os manipuladores de eventos para sincronizar os dados.

Há suporte à ligação de dados para muitas estruturas de interface do usuário, por exemplo, .NET e Eclipse / JFace .

JesperE
fonte