Domanda

Il progetto a cui sto lavorando ha appena raggiunto le 4200 righe nel file C # principale, il che fa sì che IntelliSense impieghi alcuni secondi (a volte fino a circa 6) per rispondere, durante il quale Visual Studio si blocca. Mi chiedo come tutti gli altri dividano i loro file e se c'è consenso.

Ho provato a cercare alcune guide e ho trovato Guida C ++ di Google , ma non ho potuto vedere nulla sulla semantica come dimensioni delle funzioni e dimensioni dei file; forse è lì - non lo guardo da un po '.

Quindi come dividi i tuoi file? Raggruppate i vostri metodi in base alle funzioni che servono? Per tipo (gestori di eventi, privati ??/ pubblici)? E a quale limite di dimensioni dividi le funzioni?

Per chiarire, l'applicazione in questione gestisce i dati, quindi la sua interfaccia è una griglia di grandi dimensioni e tutto ruota attorno alla griglia. Ha alcuni moduli di dialogo per la gestione, ma è tutto sui dati. Il motivo per cui è così grande è che c'è un sacco di controllo degli errori, gestione degli eventi e anche la griglia impostata come dettaglio principale con altre tre griglie per ogni riga (ma questi carichi sulla riga principale sono espansi). Spero che questo aiuti a chiarire di cosa mi occupo.

È stato utile?

Soluzione

Penso che il tuo problema sia riassunto con il termine che usi: " File C # principale " ;.

A meno che tu non intenda main (come nel metodo main ()) non c'è posto per quel concetto.

Se si dispone di una classe di utilità generale o di altri metodi comuni, è necessario suddividerli in parti funzionali simili.

In genere i miei file sono solo mappature one-to-one delle classi.

A volte le classi molto correlate si trovano nello stesso file.

Se il tuo file è troppo grande, indica che la tua classe è troppo grande e troppo generica.

Cerco di mantenere i miei metodi a metà schermo o meno. (Quando si tratta di codice che scrivo da zero, di solito sono 12 righe o meno, ma ultimamente ho lavorato sul codice esistente di altri sviluppatori e ho dovuto refactoring di 100 funzioni di linea ...)

A volte è uno schermo, ma sta diventando molto grande.

EDIT:

Per rispondere alla tua domanda sul limite di dimensione relativa alle funzioni, per me è meno una questione di dimensioni (anche se questo è un buon indicatore di un problema) e più di fare solo una cosa e mantenerne SEMPLICE.

Altri suggerimenti

Nel libro classico " Programmazione strutturata " Dijkstra una volta scrisse una sezione intitolata: "Sulla nostra incapacità di fare molto." Il suo punto era semplice. Gli umani non sono molto intelligenti. Non possiamo destreggiarci più di alcuni concetti nelle nostre menti contemporaneamente.

È molto importante mantenere le classi e i metodi piccoli. Quando un metodo supera una dozzina di righe, dovrebbe essere suddiviso. Quando una classe supera un paio di centinaia di righe, dovrebbe essere spezzata. Questo è l'unico modo per mantenere il codice ben organizzato e gestibile. Sto programmando da quasi 40 anni, e con ogni anno che passa, mi rendo conto di quanto sia importante la parola "piccola" è quando si scrive software.

Per quanto riguarda come si fa questo, questo è un argomento molto ampio che è stato scritto su molte volte diverse. Si tratta di gestione delle dipendenze, nascondimento delle informazioni e progettazione orientata agli oggetti in generale. Ecco un elenco di lettura.

Dividi i tuoi tipi dove è naturale dividerli, ma fai attenzione ai tipi che stanno facendo troppo. A circa 500 righe (di Java o C #) mi preoccupo. A circa 1000 righe comincio a capire se il tipo debba essere diviso ... ma a volte non può / non dovrebbe essere.

Per quanto riguarda i metodi: non mi piace quando non riesco a vedere l'intero metodo sullo schermo alla volta. Ovviamente dipende dalle dimensioni del monitor ecc., Ma è una regola empirica ragionevole. Preferisco che siano più brevi però. Ancora una volta, ci sono eccezioni: alcune logiche sono davvero difficili da districare, in particolare se ci sono molte variabili locali che naturalmente non vogliono essere incapsulate insieme.

A volte ha senso che un singolo tipo abbia un lotto di metodi, come System.Linq.Enumerable ma le classi parziali possono aiutare in questi casi, se puoi suddividere il tipo in gruppi logici caso di Enumerable , il raggruppamento per aggregazione / operazioni impostate / filtro ecc. sembrerebbe naturale). Tuttavia, casi simili sono rari nella mia esperienza.

Il libro di Martin Fowler Refactoring Penso che ti dia un buon punto di partenza per questo. Indica come identificare "odori di codice" e come riformattare il codice per correggere questi "odori". Il risultato naturale (sebbene non sia l'obiettivo principale) è che tu finisca con classi più piccole e più gestibili.

Modifica

Alla luce della tua modifica, ho sempre insistito sul fatto che le buone pratiche di codifica per il codice back-end sono le stesse nel livello di presentazione. Alcuni schemi molto utili da considerare per i refactoring dell'interfaccia utente sono Comando, Strategia, Specifica e Stato.

In breve, la tua vista dovrebbe contenere solo codice per gestire eventi e assegnare valori. Tutta la logica dovrebbe essere separata in un'altra classe. Una volta fatto questo, scoprirai che diventa più ovvio dove puoi fare il refactoring. Le griglie rendono questo piccolo più difficile perché rendono troppo facile dividere lo stato della presentazione tra la logica della presentazione e la vista, ma con un po 'di lavoro, puoi mettere in modo indiretto per ridurre al minimo il dolore causato da questo .

Non codificare in modo procedurale e non finirai con 4.200 righe in un file.

In C # è una buona idea aderire ad alcuni SOLID principi di progettazione orientati agli oggetti. Ogni classe dovrebbe avere una e una sola ragione per cambiare. Il metodo principale dovrebbe semplicemente avviare il punto di partenza per l'applicazione (e configurare il contenitore di iniezione delle dipendenze, se si utilizza qualcosa come StructureMap).

In genere non ho file con più di 200 righe di codice e li preferisco se sono inferiori a 100.

Non ci sono regole rigide e veloci, ma c'è un accordo generale sul fatto che più funzioni più brevi sono meglio di una singola funzione grande e più classi più piccole sono meglio di 1 classe grande.

Le funzioni più grandi di circa 40 righe dovrebbero farti pensare a come spezzarlo. Soprattutto guarda i loop nidificati, che sono confusi e spesso facili da tradurre per funzionare chiamate con bei nomi descrittivi.

Rompo le lezioni quando sento che fanno più di una cosa, come la presentazione e la logica del mix. Una grande classe è meno un problema di un grande metodo, purché la classe faccia 1 cosa.

Il consenso nelle guide di stile che ho visto è di raggruppare i metodi per accesso, con costruttori e metodi pubblici in alto. Tutto ciò che è coerente è fantastico.

Dovresti leggere sullo stile C # e sul refactoring per capire veramente i problemi che stai affrontando.

Elements of C # Style è una buona guida di stile C # per alberi morti, e questa post di blog contiene numerosi link a buone guide di stile online.

Infine, considera l'utilizzo di FxCop e StyleCop . Questi non aiuteranno con le domande che hai posto, ma possono rilevare altri problemi stilistici con il tuo codice. Dato che hai immerso la punta del piede nell'acqua, potresti anche saltare dentro.

Questo è molto, ma lo sviluppo di gusto, stile e chiarezza è una grande differenza tra buoni sviluppatori e cattivi.

Ogni classe dovrebbe fare una piccola cosa e farlo bene. La tua classe è un modulo? Quindi non dovrebbe avere NESSUNA logica aziendale in esso.

Rappresenta un singolo concetto, come un utente o uno stato? Quindi non dovrebbe avere alcun disegno, caricamento / salvataggio, ecc ...

Ogni programmatore passa attraverso fasi e livelli. Stai riconoscendo un problema con il tuo livello attuale e sei pronto per affrontare il prossimo.

Da quello che hai detto, sembra che il tuo livello attuale sia "Risolvere un problema", molto probabilmente usando il codice procedurale e devi iniziare a cercare nuovi modi per affrontarlo.

Consiglio di esaminare come realizzare davvero la progettazione OO. Ci sono molte teorie che probabilmente hai sentito che non hanno senso. Il motivo per cui non lo fanno è che non si applicano al modo in cui stai programmando.

Fammi trovare un buon post ... Dai un'occhiata a questi per iniziare:

how-do-i-break-my-procedural-coding -habits

sono-lì-qualsiasi-regole-per-oop

orientato agli oggetti-best-practice-ereditarietà-v -Composizione-v-interfacce

Ci sono anche post che rimandano a buoni libri di progettazione OO. A " Refactoring " libro è probabilmente uno dei posti migliori in cui potresti iniziare.

Sei a un buon punto in questo momento, ma non crederesti fino a che punto devi andare. Spero che tu sia entusiasta perché alcune di queste cose nel tuo prossimo futuro sono alcune delle migliori esperienze di programmazione "Apprendimento di apprendimento" che avrai mai.

Buona fortuna.

Puoi cercare piccole cose che cambiano e cambiano lentamente nel tempo.

  • Tutti i metodi sono utilizzati solo in quella classe? Cerca i metodi di supporto, come la convalida, la manipolazione delle stringhe, che possono essere spostati in classi helper / util.

  • Stai usando sezioni #region? I raggruppamenti logici di metodi correlati in una # regione spesso si prestano a essere suddivisi in classi separate.

  • La classe è un modulo? Prendi in considerazione l'utilizzo dei controlli utente per i controlli dei moduli o gruppi di controlli dei moduli.

A volte le classi di grandi dimensioni si evolvono nel tempo a causa di numerosi sviluppatori che eseguono correzioni rapide / nuove funzionalità senza considerare il design complessivo. Rivedi alcuni dei collegamenti alla teoria del design che altri hanno fornito qui e considera il supporto continuo per farli valere come revisioni del codice e workshop di gruppo per rivedere il design.

Beh, ho paura di dire che potresti avere un problema più grande a portata di mano che un tempo di caricamento lento. Incontrerai problemi di codice strettamente accoppiato e problemi di manutenibilità / leggibilità.

Ci sono ottime ragioni per dividere i file di classe in file più piccoli (e altrettanto buoni motivi per spostare i file in diversi progetti / assiemi).

Pensa a quale scopo dovrebbe raggiungere la tua classe. Ogni file dovrebbe davvero avere un solo scopo. Se è troppo generalizzato nel suo obiettivo, ad esempio " contiene la logica del carrello della spesa " ;, allora sei sulla strada sbagliata.

Inoltre, come detto, il termine che usi: " File C # principale " puzza solo di avere una mentalità molto procedurale. Il mio consiglio è di fermarmi, fare un passo indietro e avere una rapida lettura di alcuni dei seguenti argomenti:

  • Principi generali di OOP
  • Progettazione guidata dal dominio
  • Test unitari
  • IoC Contenitori

Buona fortuna con le tue ricerche.

Usa classi parziali. Fondamentalmente puoi suddividere una singola classe in più file.

Forse l'OP può rispondere: il tuo progetto utilizza la programmazione orientata agli oggetti? Il fatto che tu usi la parola "file" suggerisce che non lo è.

Fino a quando non comprendi l'orientamento agli oggetti, non c'è speranza di migliorare il tuo codice in modo importante. Faresti meglio a non dividere affatto il file, aspettare fino a quando diventa insopportabilmente lento e pieno di bug, quindi invece di sopportarlo più, vai a imparare OO.

Il parser Intellisense in Visual Studio 2008 sembra essere considerevolmente più veloce di quello del 2005 (so che hanno fatto specificatamente molto lavoro in quest'area), quindi anche se dovresti assolutamente cercare di dividere il file ad un certo punto come altri menzionato, Visual Studio 2008 potrebbe risolvere il tuo problema di prestazioni immediate. L'ho usato per aprire un file Linq to SQL 100K + line senza troppi problemi.

Dividi il codice in modo che ogni classe / file / funzione / ecc. fa solo una cosa & # 8482 ;. The Single Responsibility Principle è una buona linea guida per suddividere la funzionalità in classi.

Al giorno d'oggi, le classi più grandi che scrivo sono lunghe circa 200 righe e i metodi sono prevalentemente di 1-10 righe.

Se all'interno di una classe sono presenti aree di codice, un metodo semplice consiste nell'utilizzare la parola chiave parziale e suddividere quella definizione della classe in quel file. In genere lo faccio per grandi classi.

La convenzione che uso è di avere ClassName_RegionName.cs. Ad esempio, se voglio interrompere una classe che gestisce lo schema per una connessione al database e ho chiamato la classe DatabaseConnection, creerei un file chiamato DatabaseConnection.cs per la classe principale e quindi DatabaseConnection_Schema.cs per la funzionalità dello schema.

Alcune classi devono solo essere grandi. Non è un cattivo design; sono solo pesanti da implementare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top