Come si può evitare di scrivere codice GUI gonfio?


48

Trovo che quando lavoro con il codice GUI, il codice tende a gonfiarsi più velocemente di altri tipi di codice. Sembra anche più difficile rifattorizzare. Mentre in altri tipi di codice posso refactificare abbastanza facilmente - trovo che posso scomporre una classe più grande in piccoli pezzi di funzionalità - con la maggior parte dei framework GUI sono spesso legato a un framework che richiede il mio widget / controllo / qualunque classe per implementare molte più cose direttamente nel widget / controllo / qualunque cosa. A volte ciò è dovuto alla necessità di (a) ereditare da alcuni widget / controlli / cose di base o (b) accedere a metodi protetti.

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

  1. un tasto destro / menu contestuale
  2. reagire alle selezioni dal menu contestuale - che possono essere molte
  3. un modo speciale per dipingere la GUI
  4. reagire all'input da tastiera
  5. pulsanti, caselle di controllo,
  6. ecc ecc

... nel frattempo gestisci le classi sotto la GUI che rappresentano la logica aziendale.

Una semplice GUI diretta può far crescere il suo codice abbastanza rapidamente, anche se separando la logica di business e usando MVC, trovo che il codice GUI sia un grande magnete per il cambiamento.

Esiste un modo per gestire il codice della GUI in modo sano ed evitare di farlo diventare una finestra rotta? Oppure una massa di gestori di eventi casuali / metodi ignorati è davvero la migliore che possiamo fare per il codice della GUI?


4
Qual è la tua esatta definizione di "gonfiare"?

Risposte:


36

La cosa da ricordare sul codice della GUI è che è guidato dagli eventi e che il codice guidato dagli eventi avrà sempre l'aspetto di una massa di gestori di eventi organizzati in modo casuale. Il punto in cui diventa davvero disordinato è quando si tenta di inserire nella classe codice non guidato da eventi. Certo, ha l'aspetto di fornire supporto ai gestori di eventi e puoi mantenere i gestori di eventi simpatici e piccoli, ma tutto quel codice di supporto extra che fluttua intorno rende la tua fonte di GUI gonfia e disordinata.

Quindi cosa puoi fare al riguardo e come puoi semplificare il refactoring delle cose? Bene, per prima cosa cambierei la mia definizione di refactoring da qualcosa che faccio occasionalmente a qualcosa che faccio continuamente mentre scrivo. 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 calisthenics mentale per vedere il tuo codice in modo diverso.

Le tre tecniche di refactoring che trovo più comunemente usate sono Rinomina , Metodo di estrazione e Classe di estrazione . Se non avessi mai imparato un singolo 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 ritroverai a utilizzare gli stessi tre refactoring quasi costantemente in per mantenere il tuo codice GUI sottile e pulito.

Puoi avere la migliore separazione possibile della GUI e della logica aziendale al mondo, eppure il codice GUI può apparire come un mio codice è stato fatto esplodere nel mezzo di esso. Il mio consiglio è che non guasta avere una o due classi extra per aiutarti a gestire correttamente la tua GUI, e questa non deve necessariamente essere la tua classe View se stai applicando il pattern MVC - anche se spesso troverai le classi intermedie sono così simili al tuo punto di vista che spesso sentirai il bisogno di unirle per comodità. La mia opinione su questo è che non fa male aggiungere un ulteriore livello specifico della GUI per gestire tutta la logica visiva, tuttavia probabilmente vorrai valutare i vantaggi e i costi di farlo.

Il mio consiglio quindi è:

  • Non fare nulla direttamente dietro la tua GUI se non per invocare e definire come la GUI si aggancerà alla Vista (o ad un livello intermedio).
  • Non cercare di inserire tutte le cose relative alla vista in una singola classe - o anche in una singola classe per finestra della GUI - a meno che non abbia senso farlo. La tua alternativa è quella di creare molte classi piccole e facili da gestire per gestire la tua logica della GUI.
  • Quando i tuoi metodi stanno iniziando a sembrare un po 'più grandi di 4-5 righe di codice, esamina se questo è necessario e se è possibile estrarre un metodo o due in modo da poter mantenere i tuoi metodi snelli, anche se questo significa una classe con molti altri metodi.
  • Se le tue classi stanno iniziando a sembrare davvero grandi, inizia rimuovendo TUTTE le funzionalità duplicate, quindi vedi se riesci a raggruppare logicamente i tuoi metodi in modo da poter estrarre un'altra o due classi.
  • Pensa al refactoring ogni volta che scrivi una riga di codice. Se riesci a far funzionare una riga di codice, vedi se riesci a riformattarla per evitare la duplicazione della funzionalità o per renderla un po 'più snella senza cambiare il comportamento.
  • Accetta l'inevitabile, che sentirai sempre che una parte o l'altra nel tuo sistema inizierà a sentirsi un po 'gonfia, specialmente se trascuri il refactoring mentre procedi. Anche con una base di codice ben ponderata, puoi comunque avere la sensazione di poter fare di più. Questa è la realtà della scrittura di software, che ti farà sempre sentire che qualcosa di più avrebbe potuto essere fatto "meglio", quindi devi trovare un equilibrio tra fare un lavoro professionale e la doratura.
  • Accetta che più pulito provi e mantieni il tuo codice, meno il tuo codice sembrerà gonfio.

3
+1 Piaccia o no, una GUI si occupa di un milione di operazioni dettagliate e questo significa codice.
Patrick Hughes,

Gli sviluppatori dovrebbero imparare a utilizzare la codifica basata su eventi per la GUI.
David Gao,

23

Penso che molti dei problemi che stai riscontrando possano essere ricondotti a una semplice causa. La maggior parte degli sviluppatori non tratta il codice della GUI come un codice "reale". Non ho prove o statistiche qui, solo il mio istinto.

Forse pensano che sia " solo una presentazione " e non importante. " Non esiste alcuna logica commerciale ", dicono, " perché l'unità lo verifica "? Ridono quando menzioni l'orientamento agli oggetti e scrivono codice pulito. Non provano nemmeno a migliorare le cose. Non esiste una struttura con cui iniziare, prendono semplicemente un po 'di codice e lo lasciano marcire mentre altri aggiungono il loro tocco nel tempo. Un bel pasticcio, codice graffiti.

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


2
+1 per alludere alla percezione del codice GUI trattato in modo diverso dal codice non gui. Ho perso il conto del numero di volte in cui ho sentito qualcuno dire "non preoccuparti di testare la GUI perché non è conveniente e inoltre è così difficile da fare". Di solito traduco in "È difficile e sono troppo pigro per imparare a farlo!".
S.Robins,

1
+1 Dove lavoro spesso non esaminiamo il codice della GUI - "è solo la GUI, saltalo". E sono colpevole come chiunque altro. La cosa strana è che nei miei progetti personali passo molto tempo se cerco di ottenere un bel codice GUI pulito. Immagino sia solo una questione di cultura.
HappyCat,

8

Per qualche ragione il codice della GUI crea un punto cieco negli sviluppatori sulla separazione dei problemi. Forse è perché tutti i tutorial raggruppano tutto in una classe. Forse è perché la rappresentazione fisica fa sembrare le cose più strettamente accoppiate di quanto non siano. Forse è perché le classi si sviluppano lentamente in modo che le persone non riconoscano di aver bisogno di refactoring, come la proverbiale rana che viene bollita aumentando lentamente il calore.

Qualunque sia il motivo, la soluzione è rendere le tue lezioni molto più piccole. Lo faccio chiedendomi continuamente se è possibile mettere ciò che sto scrivendo in una classe separata. Se è possibile inserirsi in un'altra classe e riesco a pensare a un nome ragionevole e semplice per quella classe, allora lo faccio.


6

Potresti dare un'occhiata al modello Vista modello / Vista vista passiva. Ray Ryan ha tenuto una buona chiacchierata su un IO di Google sulle migliori pratiche di architettura per GWT.

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

È facile astrarre le idee su altri framework e linguaggi. Il vantaggio principale di MVP (secondo me) è 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 logico di vista chiamato presentatore. La vista effettiva è disaccoppiata da questo tramite un'interfaccia (e quindi può essere facilmente derisa nei test unitari). Ora, poiché il tuo livello logico di visualizzazione (il presentatore) viene liberato dagli interni del framework GUI concreto, puoi organizzarlo come un normale codice e non sei legato ad esempio alla gerarchia dell'ereditarietà di Swings. Idealmente, è possibile cambiare le implementazioni della GUI in diversi framework purché siano conformi alla stessa interfaccia.


1
+1. MVP si concentra esattamente su come estrarre la logica della GUI in classi separate, che è spesso molto diversa da ciò che la gente capisce quando parla di MVC.
Doc Brown,

5

La mia risposta è composta da quattro parti: struttura, semplicità, test e sintassi.

I primi tre sono davvero difficili da fare!

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

Semplicità significa mantenere le cose semplici dalla progettazione iniziale all'implementazione 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 mio lavoro di rotaie) che rilevano in anticipo i problemi tra browser quando è possibile progettare un codice migliore per gestirli all'inizio invece del frequente "patching" del codice da sviluppatori diversi in quanto "scoperti" da utenti di browser diversi.

Sintassi. È davvero utile usare un controllo del codice / IDE / editor-plugin, ecc. Per HTML, CSS, Javascript, ecc. quindi uno strumento che controlla il tuo formato HTML è essenziale. Avere HTML ben formato è molto utile per avere HTML non utilizzato poiché un codice errato dovrebbe avere maggiore visibilità.


4

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


4

Ci sono molte grandi risposte qui.

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

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

Progetto una GUI come modello - vista. Il modello GUI è controllato dal controller dell'applicazione del modello dell'applicazione - view - controller. La vista dell'applicazione è il modello GUI, piuttosto che il codice GUI stesso.


2

Applicazioni come elaborazione testi, editor di 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 in alcuni casi è ancora così.

Alcune delle chiavi per semplificare la GUI sono (la maggior parte si applica a .NET):

  1. Sforzati per un design più semplice quando possibile. Evitare comportamenti fantasiosi se non richiesto dall'azienda.

  2. Usa 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 da poter riflettere i tuoi comportamenti specifici nei controlli piuttosto che nel codice del modulo / pagina usando.

  4. Utilizza un framework (anche una casa) per gestire l'internazionalizzazione, la gestione delle risorse, gli stili, ecc. In modo da non ripetere questo codice in ogni interfaccia utente.

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

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


1

Applica la progettazione orientata agli oggetti al tuo codice e per lo sviluppo dell'interfaccia utente:

  1. Presentazione e modello separati Utilizzare una libreria / framework MV qualunque, o scrivere la propria, per aiutare a separare la logica di visualizzazione / controller dal modello di dati. Tutte le comunicazioni con il backend devono essere eseguite all'interno del modello e lo stato del modello deve essere sempre sincronizzato con il backend.
  2. Disaccoppiamento Se l'oggetto A è a conoscenza dell'oggetto B, allora A può chiamare i metodi su B, ma B non dovrebbe sapere di A. Invece A può ascoltare gli eventi da B. Si assicura che non vi sia dipendenza circolare. Se la tua app ha molti eventi tra i componenti, crea un EventBus o sfrutta un framework basato sugli 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 nella / dalla raccolta. Il tuo codice potrebbe facilmente gonfiarsi quando devi supportare l'ordinamento e l'impaginazione. Quindi il mio consiglio è: semplicemente riattivare l'intera vista anche quando c'è un cambiamento parziale. E le prestazioni? bene se la tua collezione è grande, allora dovresti fare comunque l'impaginazione. Sviluppatore Web: assicurati che i gestori di eventi siano delegati all'elemento radice della vista che non cambia.
  4. Modello di visualizzazione Quando lo stato della visualizzazione diventa troppo complicato per mantenere, ad esempio, una vista Tabella deve tenere traccia dei dati di riga, dei dati di colonna, dell'ordinamento, delle righe attualmente controllate (se supporta il controllo multiplo), ecc. creare un oggetto ViewModel per quegli stati. L'oggetto View dovrebbe chiamare setter su ViewModel se qualcosa cambia nell'interfaccia utente (ad 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 modifica viene attivato dall'interfaccia utente.

Ecco un'app piccola ma non banale per illustrare alcuni dei miei punti. Puoi trovare il codice e visualizzare il diagramma di interazione del modello qui: https://github.com/vanfrankie/pushpopbox


0

Volete dare un'occhiata al concetto di "database" . In questo modo è possibile connettere gli elementi dell'interfaccia utente agli elementi astratti del modello in modo dichiarativo in modo tale che gli elementi del modello vengano automaticamente sincronizzati con il contenuto dell'interfaccia utente. Ci sono molti vantaggi di questo approccio, ad esempio non dover scrivere personalmente i gestori di eventi per sincronizzare i dati.

È disponibile il supporto di database per molti framework dell'interfaccia utente, ad esempio .NET ed Eclipse / JFace .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.