Come si può evitare di scrivere codice GUI gonfio?

46

Trovo che ogni volta che lavoro con il codice GUI, il codice tende a gonfiarsi più velocemente di altri tipi di codice. Sembra anche più difficile da refactoring. Mentre in altri tipi di codice posso facilmente refactoring - trovo che posso scomporre una classe più grande in parti più piccole di funzionalità - con la maggior parte dei framework GUI sono spesso legato a un framework che richiede il mio widget / controllo / qualsiasi classe per implementa molte più cose direttamente nel widget / controllo / qualsiasi cosa. A volte ciò è dovuto alla necessità di (a) ereditare da qualche widget / controllo / cosa di base o (b) necessità di accedere a metodi protetti.

In genere, ad esempio, devo rispondere a una grande varietà di input tramite segnali / eventi / qualsiasi cosa dal framework per implementare tutte le modalità di interazione con l'utente. Potrei aver bisogno di un widget / controllo della GUI per gestire una grande varietà di input / output che potrebbe includere:

  1. un clic destro / menu contestuale
  2. reagendo alle selezioni dal menu di scelta rapida, che potrebbe essere molti
  3. un modo speciale per dipingere la GUI
  4. reagisce all'input della tastiera
  5. pulsanti, caselle di controllo,
  6. ecc. ecc.

... per tutto il tempo gestisci le classi sotto la GUI che rappresentano la logica di business.

Una GUI semplice e diretta può avere il suo codice crescere abbastanza rapidamente, anche quando si separa la logica di buisiness e usando MVC, trovo che il codice GUI sia un grande magnete per il cambiamento.

C'è un modo per gestire il codice GUI in modo sano ed evitare che diventi una finestra rotta? O una massa di gestori di eventi casuali / metodi sovrascritti è davvero il meglio che possiamo fare per il codice GUI?

    
posta Doug T. 17.04.2012 - 02:31
fonte

10 risposte

36

La cosa da ricordare sul codice GUI è che è basata sugli eventi e il codice basato sugli eventi avrà sempre l'aspetto di una massa di gestori di eventi organizzati casualmente. Dove diventa davvero complicato è quando si tenta di calzare codice non guidato da eventi nella classe. Certo, ha l'apparenza di fornire supporto per i gestori di eventi e puoi mantenere i tuoi gestori di eventi semplici e piccoli, ma tutto quel codice di supporto extra che galleggia intorno rende la tua sorgente GUI apparentemente gonfia e disordinata.

Che cosa puoi fare al riguardo e come puoi rendere le cose più facili da refactoring? Bene, per prima cosa cambierei la mia definizione di refactoring da qualcosa che faccio in occasione di qualcosa che faccio continuamente mentre codice. Perché? Perché vuoi che il refactoring ti permetta di modificare più facilmente il tuo codice, e non viceversa. Non ti sto semplicemente chiedendo di cambiare la semantica qui, ma ti chiedo invece di fare un po 'di ginnastica ritmica per vedere il tuo codice in modo diverso.

Le tre tecniche di refactoring che trovo di utilizzare più comunemente sono Rinomina , Estrai metodo e Estrai classe . Se non avessi mai imparato un altro refactoring, quei tre mi avrebbero comunque permesso di mantenere il mio codice pulito e ben strutturato, e dal contenuto della tua domanda, mi sembra che probabilmente ti ritrovi ad utilizzare gli stessi tre refactoring quasi costantemente in per mantenere il codice GUI sottile e pulito.

Puoi avere la migliore separazione possibile tra la GUI e la logica aziendale nel mondo, e il codice della GUI può ancora apparire come un codice che è stato detonato nel bel mezzo di esso. Il mio consiglio è che non fa male avere una classe o due in più per aiutarti a gestire correttamente la tua GUI, e questo non deve essere necessariamente la tua classe Visualizza se stai applicando il pattern MVC - anche se spesso troverai che le classi intermedie sono così simili alla tua opinione che sentirai spesso la necessità di unirle per comodità. La mia opinione su questo è che non fa davvero male aggiungere un ulteriore livello specifico della GUI per gestire tutta la logica visiva, tuttavia probabilmente vorrai valutare i vantaggi e i costi di ciò.

Il mio consiglio è quindi:

  • Non fare nulla direttamente dietro la GUI tranne che per invocare e definire in che modo la GUI si agganci alla vista (o a un livello intermedio).
  • Non provare a eseguire il corno della scarpa ogni cosa relativa alla vista in una singola classe, o persino una singola classe per finestra della GUI, a meno che non abbia senso per te farlo. La tua alternativa è creare molte classi piccole e facili da gestire per gestire la tua logica della GUI.
  • Quando i tuoi metodi cominciano a sembrare un po 'più grandi di 4-5 linee di codice, verifica se è necessario e se è possibile estrarre un metodo o due in modo da mantenere i metodi snelli, anche se questo significa una classe con molti altri metodi.
  • Se le tue classi iniziano a sembrare davvero grandi, inizia rimuovendo TUTTE le funzionalità duplicate, quindi verifica se puoi raggruppare logicamente i tuoi metodi in modo da poterne estrarre un'altra o due.
  • Pensa al refactoring ogni volta che scrivi una riga di codice. Se riesci a far funzionare una riga di codice, verifica se è possibile eseguire il refactoring per evitare la duplicazione della funzionalità o per renderla un po 'più snella senza modificare il comportamento.
  • Accetta l'inevitabile, che sentirai sempre che una parte o l'altra del tuo sistema inizieranno a sentirsi un po 'gonfie, specialmente se trascuri il refactoring mentre procedi. Anche con una base di codice ben strutturata, puoi ancora sentire come se ci fosse più che potresti fare. Questa è la realtà del software di scrittura, che ti sentirai sempre alla sensazione che qualcosa di più avrebbe potuto essere fatto "meglio", quindi devi trovare un equilibrio tra fare un lavoro professionale e placcare oro.
  • Accetta che il pulitore cerchi di mantenere il tuo codice, meno il tuo codice sembrerà gonfio.
risposta data 17.04.2012 - 04:54
fonte
22

Penso che molti dei problemi che stai vivendo possano essere ricondotti a una causa semplice. La maggior parte degli sviluppatori non tratta il codice GUI come codice "reale". Non ho prove o statistiche qui, solo la mia sensazione istintiva.

Forse pensano che sia ' solo presentazione ' e non importante. ' Non esiste una logica aziendale ', si dice, ' perché unità testarlo '? Ridono quando menzioni l'orientamento all'oggetto e scrivi codice pulito. Non provano nemmeno a migliorare le cose. Non c'è una struttura da cui iniziare, semplicemente schiaffo un po 'di codice e lo lascia marcire mentre altri aggiungono il proprio tocco nel tempo. Un bel casino, codice dei graffiti.

Il codice GUI ha le sue sfide uniche quindi deve essere trattato in modo diverso e con rispetto. Ha bisogno di amore e sviluppatori che vogliono per scriverlo. Quelli che lo manterranno sottili e gli daranno una buona struttura e modelli corretti.

    
risposta data 17.04.2012 - 03:29
fonte
7

Per qualche motivo il codice GUI crea un punto cieco negli sviluppatori sulla separazione delle preoccupazioni. Forse è perché tutte le esercitazioni raggruppano tutto in un'unica classe. Forse è perché la rappresentazione fisica fa sembrare le cose più strettamente accoppiate di quello che sono. Forse perché le lezioni si accumulano lentamente, così le persone non riconoscono di aver bisogno di un refactoring, come la rana proverbiale che viene bollita lentamente alzando il calore.

Qualunque sia la ragione, la soluzione è di rendere le tue lezioni molto più piccole. Lo faccio chiedendomi continuamente se è possibile inserire ciò che sto digitando in una classe separata. Se è possibile mettere in un'altra classe, e posso pensare ad un nome ragionevole e semplice per quella classe, allora lo faccio.

    
risposta data 17.04.2012 - 19:45
fonte
5

Potrebbe essere utile dare uno sguardo al modello View Viewer / Passive View. Ray Ryan ha tenuto una buona conversazione su un IO di Google sulle migliori pratiche di architettura per GWT.

link

È facile astrarre le idee ad altri framework e linguaggi. Il principale vantaggio di MVP (a mio parere) è la testabilità dell'unità. E lo ottieni solo, se il tuo codice non è gonfio e non spaghetti (a giudicare dalla tua domanda, questo è quello che vuoi). Funziona introducendo un livello di logica di visualizzazione chiamato presentatore. La vista effettiva viene disaccoppiata da questa tramite un'interfaccia (e quindi può essere facilmente derisa nei test di unità). Ora, dal momento che il livello di logica di visualizzazione (il relatore) viene liberato dall'interno del framework GUI concreto, puoi organizzarlo come un normale codice e non sei legato ad es. Oscillazione gerarchia ereditarietà. Idealmente è possibile cambiare le implementazioni della GUI in diversi framework purché conformi alla stessa interfaccia.

    
risposta data 17.04.2012 - 12:29
fonte
5

La mia risposta consiste di quattro parti: struttura, semplicità, test e sintassi.

I primi tre sono davvero difficili da fare!

Struttura significa prestare molta attenzione all'utilizzo della quantità minima di codice e della quantità massima di framework, librerie, ecc.

Semplicità significa mantenere le cose semplici dalla progettazione iniziale all'attuazione effettiva. Mantenere la navigazione semplice, usando semplici plugin, mantenendo il layout abbastanza "semplice" aiuterà tutti qui. Ora possono essere "venduti" a clienti / utenti che possono vedere rapidamente i vantaggi delle pagine che funzionano su PC, iPad, dispositivi mobili e altri dispositivi.

Test significa includere strumenti di test del browser (webrat e capybara vengono in mente con il lavoro sulle mie rotaie) che catturano i problemi del browser quando è possibile progettare un codice migliore per affrontarli all'inizio al contrario delle frequenti "patching" di codice da parte di diversi sviluppatori che vengono "scoperti" dagli utenti di browser diversi.

Sintassi. È molto utile usare un correttore di codice / IDE / editor-plug-in, ecc. Per il tuo HTML, CSS, Javascript, ecc. Il vantaggio che i browser hanno ottenuto essendo in grado di gestire l'HTML malformato funziona contro di te quando diversi browser eseguono in modo diverso con così, uno strumento che verifica il tuo formato HTML è essenziale. Avere un HTML ben formato è di grande aiuto nell'offrire HTML in quanto codice errato dovrebbe avere maggiore visibilità.

    
risposta data 17.04.2012 - 03:00
fonte
4

La soluzione che ho trovato è un codice dichiarativo. L'uso di un codice procedurale è una ricetta per il codice GUI degli spaghetti. Certo, un "modo speciale per dipingere il widget" probabilmente rimarrà un codice. Ma questo è un codice isolato in una classe. Gestori di eventi, scorciatoie da tastiera, dimensioni delle finestre: tutto ciò che è confuso è meglio dichiararlo.

    
risposta data 17.04.2012 - 14:12
fonte
4

Qui ci sono un sacco di ottime risposte.

Una cosa che mi ha aiutato a semplificare il codice GUI è assicurarsi che la GUI abbia il proprio modello di dati.

Per fare un semplice esempio, se ho una GUI con 4 campi di immissione del testo, allora ho una classe dati separata che mantiene il contenuto di quei 4 campi di immissione del testo. Le GUI più complesse richiedono più classi di dati.

Disegnare una GUI come vista del modello. Il modello della GUI è controllato dal controller dell'applicazione del modello di applicazione - view - controller. La vista dell'applicazione è il modello della GUI, piuttosto che il codice della GUI stessa.

    
risposta data 18.04.2012 - 15:41
fonte
2

Applicazioni come Elaborazione testi, Editor grafici, ecc. hanno interfacce complesse e il loro codice non può essere semplice. Tuttavia, per le applicazioni aziendali, la GUI non deve essere così complessa, ma alcuni sono ancora così.

Alcuni dei tasti per semplificare la GUI sono (la maggior parte si applicano a .NET):

  1. Cerca di avere un design più semplice quando possibile. Evita i comportamenti di fantasia se non richiesto dall'azienda.

  2. Utilizza un buon fornitore di controlli.

  3. Non creare funzionalità di controllo personalizzate nel codice client stesso. Invece, crea controlli utente che estendono il controllo originale in modo tale che puoi riflettere i tuoi comportamenti specifici nei controlli piuttosto che nel codice del modulo / pagina di utilizzo.

  4. Utilizza un framework (anche a livello nazionale) per gestire internazionalizzazione, gestione delle risorse, stili, ecc. in modo da non ripetere questo codice in ogni interfaccia utente.

  5. Utilizza un componente (o un framework) per la navigazione.

  6. Crea dialoghi standard per errori, avvisi, conferme, ecc.

risposta data 17.04.2012 - 04:45
fonte
1

Applica il design orientato agli oggetti al tuo codice e per lo sviluppo dell'interfaccia utente:

  1. Presentazione e modello separati Utilizzare una libreria / framework MV-any o scrivere la propria per aiutare a separare la logica di visualizzazione / controllore dal modello di dati. Tutte le comunicazioni con il back-end devono essere eseguite all'interno del modello e lo stato del modello deve essere sempre sincronizzato con il back-end.
  2. Il disaccoppiamento Se l'oggetto A conosce l'oggetto B, allora A può chiamare metodi su B, ma B non dovrebbe sapere di A. Invece A può ascoltare eventi da B. Si assicura che non ci sia alcuna dipendenza circolare. Se la tua app ha molti eventi tra i componenti, crea un EventBus o sfrutta un framework basato su eventi come Twitter Flight.
  3. Rendering parziale o completo se la tua vista è una tabella o un elenco di elementi, potresti essere tentato di creare metodi come "aggiungi", "rimuovi" per inserire / eliminare un elemento in / dalla raccolta. Il tuo codice potrebbe facilmente gonfiarsi quando devi supportare l'ordinamento e l'impaginazione. Quindi il mio consiglio è: semplicemente ridisegnare l'intera vista anche quando c'è un cambiamento parziale. Che dire delle prestazioni? beh se la tua collezione è grande, allora dovresti fare l'impaginazione comunque. Sviluppatore Web: assicurati che i gestori di eventi siano delegati all'elemento radice della vista che non cambia.
  4. Visualizza modello Quando lo stato della vista diventa troppo complicato da mantenere, ad esempio, una vista Tabella deve tenere traccia dei dati delle righe, dei dati della colonna, dell'ordinamento, delle righe correntemente controllate (se supporta il controllo multiplo ), ecc, probabilmente dovresti creare un oggetto ViewModel per quegli stati. L'oggetto View dovrebbe chiamare setter sul ViewModel se qualcosa cambia sull'interfaccia utente (es .: l'utente controlla una riga); e dovrebbe rispondere all'evento di modifica di ViewModel aggiornando l'interfaccia utente. Di solito dovresti evitare di aggiornare l'interfaccia utente se l'evento di cambiamento è trigger per l'interfaccia utente.

Ecco una piccola ma non banale app per illustrare alcuni dei miei punti. Puoi trovare il codice e il diagramma di interazione vista / modello qui: link

    
risposta data 04.03.2013 - 00:27
fonte
0

Vuoi dare un'occhiata al concetto di "associazione dati" . Questo è un modo per collegare gli elementi dell'interfaccia utente agli elementi del modello astratto in modo dichiarativo in modo tale che gli elementi del modello siano automaticamente sincronizzati con i contenuti dell'interfaccia utente. Ci sono molti vantaggi di questo approccio, ad esempio non dover scrivere autonomamente gestori di eventi per sincronizzare i dati.

È disponibile il supporto per i database per molti framework UI, ad esempio .NET e Eclipse / JFace .

    
risposta data 04.03.2013 - 08:20
fonte

Leggi altre domande sui tag