#Regioni sono un antipattern o un odore di codice?


267

C # consente l'uso di #region/ #endregionparole chiave per rendere aree di codice pieghevoli nell'editor. Ogni volta che lo faccio, però lo faccio per nascondere grossi blocchi di codice che probabilmente potrebbero essere refactored in altre classi o metodi. Ad esempio ho visto metodi che contengono 500 righe di codice con 3 o 4 regioni solo per renderlo gestibile.

Quindi l'uso giudizioso delle regioni è un segnale di difficoltà? Sembra essere così per me.


9
Cordiali saluti: CodeMap elimina praticamente le esigenze delle regioni. visualstudiogallery.msdn.microsoft.com/… - Fai clic su per accedere al metodo / attributo / qualunque cosa. Lo uso ogni giorno ed è incredibile quanto guadagni in termini di produttività e anche cognitivi. Ottieni una visione molto più chiara della classe.

7
Qualcuno può renderlo un wiki? Non esiste una risposta giusta o sbagliata a questa domanda (beh, entro limiti ragionevoli), è quasi completamente soggettiva.
Ed S.

6
Per quello che vale, Jeff Atwood li odia . Sostiene che nascondono codice errato.
Brian,

3
L'odore di codice è uno sviluppatore che non fa la doccia e non usa un deodorante!
marko,

5
Regioni realizzate con cura in codice puzzolente sono ciò che fanno alcune spremute di Febreeze su un divano croccante. Lo rende sopportabile fino a quando non trovi il (tempo) denaro per sostituirlo.
Newtopian,

Risposte:


285

Un odore di codice è un sintomo che indica che esiste un problema nella progettazione che potrebbe potenzialmente aumentare il numero di bug: questo non è il caso delle regioni, ma le regioni possono contribuire a creare odori di codice, come i metodi lunghi.

Da:

Un anti-pattern (o antipattern) è un pattern utilizzato in operazioni sociali o aziendali o ingegneria del software che può essere comunemente usato ma è inefficace e / o controproducente nella pratica

le regioni sono anti-schemi. Richiedono più lavoro che non aumenta la qualità o la leggibilità del codice, che non riduce il numero di bug e che può solo rendere il codice più complicato per refactoring.

Non usare le regioni all'interno dei metodi; refactor invece

I metodi devono essere brevi . Se ci sono solo dieci righe in un metodo, probabilmente non useresti le regioni per nasconderne cinque quando lavori su altre cinque.

Inoltre, ogni metodo deve fare una e una sola cosa . Le regioni, d'altra parte, hanno lo scopo di separare cose diverse . Se il tuo metodo fa A, quindi B, è logico creare due regioni, ma questo è un approccio sbagliato; invece, dovresti riformattare il metodo in due metodi separati.

L'uso delle regioni in questo caso può anche rendere più difficile il refactoring. Immagina di avere:

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    if (!verification)
    {
        throw new DataCorruptedException();
    }

    Do(data);
    DoSomethingElse(data);
    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine();
    auditEngine.Submit(data);
    #endregion
}

Il collasso della prima regione per concentrarsi sulla seconda non è solo rischioso: possiamo facilmente dimenticare l'eccezione che interrompe il flusso (potrebbe esserci una clausola di guardia con un returninvece, che è ancora più difficile da individuare), ma avrebbe anche un problema se il codice deve essere refactored in questo modo:

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    var info = DoSomethingElse(data);

    if (verification)
    {
        Do(data);
    }

    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine(info);
    auditEngine.Submit(
        verification ? new AcceptedDataAudit(data) : new CorruptedDataAudit(data));
    #endregion
}

Ora, le regioni non hanno senso e non è possibile leggere e comprendere il codice nella seconda regione senza guardare il codice nella prima.

Un altro caso che a volte vedo è questo:

public void DoSomething(string a, int b)
{
    #region Validation of arguments
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }
    #endregion

    #region Do real work
    ...
    #endregion
}

È allettante utilizzare le regioni quando la convalida degli argomenti inizia a decine di LOC, ma esiste un modo migliore per risolvere questo problema: quello utilizzato dal codice sorgente di .NET Framework:

public void DoSomething(string a, int b)
{
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }

    InternalDoSomething(a, b);
}

private void InternalDoSomething(string a, int b)
{
    ...
}

Non utilizzare le regioni al di fuori dei metodi per raggruppare

  • Alcune persone li usano per raggruppare campi, proprietà, ecc. Questo approccio è sbagliato: se il codice è conforme a StyleCop, i campi, le proprietà, i metodi privati, i costruttori, ecc. Sono già raggruppati e facili da trovare. In caso contrario, è il momento di iniziare a pensare di applicare regole che garantiscano l'uniformità in tutta la base di codice.

  • Altre persone usano le regioni per nascondere molte entità simili . Ad esempio, quando hai una classe con centinaia di campi (che crea almeno 500 righe di codice se conti i commenti e lo spazio bianco), potresti essere tentato di mettere quei campi all'interno di una regione, comprimerlo e dimenticartene. Ancora una volta, stai sbagliando: con così tanti campi in una classe, dovresti pensare meglio all'uso dell'ereditarietà o suddividere l'oggetto in più oggetti.

  • Infine, alcune persone sono tentate di usare le regioni per raggruppare cose correlate : un evento con il suo delegato o un metodo correlato all'IO con altri metodi relativi all'IO, ecc. Nel primo caso, diventa un casino che è difficile da mantenere , leggi e capisci. Nel secondo caso, il miglior progetto sarebbe probabilmente quello di creare diverse classi.

C'è un buon uso per le regioni?

No. C'era un uso legacy: codice generato. Tuttavia, gli strumenti di generazione del codice devono solo utilizzare classi parziali. Se C # ha il supporto per le regioni, è principalmente dovuto a questo uso legacy e perché ora che troppe persone hanno usato le regioni nel loro codice, sarebbe impossibile rimuoverle senza rompere le basi di codice esistenti.

Pensa a questo proposito goto. Il fatto che la lingua o l'IDE supporti una funzione non significa che debba essere utilizzata quotidianamente. La regola StyleCop SA1124 è chiara: non si devono usare le regioni. Mai.

Esempi

Attualmente sto facendo una revisione del codice del codice del mio collega. La base di codice contiene molte regioni ed è in realtà un perfetto esempio sia di come non utilizzare le regioni sia del perché le regioni portano a codici errati. Ecco alcuni esempi:

4000 mostro LOC:

Di recente ho letto da qualche parte su Programmers.SE che quando un file contiene troppi usings (dopo aver eseguito il comando "Rimuovi Usi inutilizzati"), è un buon segno che la classe all'interno di questo file sta facendo troppo. Lo stesso vale per le dimensioni del file stesso.

Durante la revisione del codice, mi sono imbattuto in un file LOC da 4 000. Sembra che l'autore di questo codice abbia semplicemente copiato e incollato lo stesso metodo a 15 righe centinaia di volte, modificando leggermente i nomi delle variabili e il metodo chiamato. Un semplice regex ha permesso di tagliare il file da 4000 LOC a 500 LOC, semplicemente aggiungendo alcuni generici; Sono abbastanza sicuro che con un refactoring più intelligente, questa classe potrebbe essere ridotta a poche decine di righe.

Usando le regioni, l'autore si è incoraggiato a ignorare il fatto che il codice è impossibile da mantenere e scritto male, e a duplicare pesantemente il codice invece di riformattarlo.

Regione “Do A”, Regione “Do B”:

Un altro esempio eccellente è stato un metodo di inizializzazione dei mostri che ha semplicemente svolto l'attività 1, quindi l'attività 2, quindi l'attività 3, ecc. Vi erano cinque o sei attività totalmente indipendenti, ciascuna delle quali inizializzava qualcosa in una classe container. Tutte queste attività sono state raggruppate in un metodo e raggruppate in regioni.

Questo ha avuto un vantaggio:

  • Il metodo era abbastanza chiaro da capire guardando i nomi delle regioni. Detto questo, lo stesso metodo, una volta refactored, sarebbe chiaro come l'originale.

I problemi, d'altra parte, erano molteplici:

  • Non era ovvio se esistessero dipendenze tra le regioni. Speriamo che non ci fosse riutilizzo delle variabili; altrimenti, la manutenzione potrebbe essere un incubo ancora di più.

  • Il metodo era quasi impossibile da testare. Come faresti facilmente a sapere se il metodo che fa venti cose alla volta le fa correttamente?

Regione dei campi, regione delle proprietà, regione del costruttore:

Il codice rivisto conteneva anche molte regioni che raggruppavano tutti i campi insieme, tutte le proprietà insieme, ecc. Questo aveva un ovvio problema: la crescita del codice sorgente.

Quando apri un file e vedi un enorme elenco di campi, sei più propenso a refactificare prima la classe, quindi lavorare con il codice. Con le regioni, prendi l'abitudine di far crollare cose e dimenticartene.

Un altro problema è che se lo fai ovunque, ti ritroverai a creare regioni a un blocco, il che non ha alcun senso. Questo è stato in realtà il caso del codice che ho recensito, in cui c'erano molti #region Constructorcontenuti contenenti un costruttore.

Infine, campi, proprietà, costruttori ecc. Dovrebbero già essere in ordine . Se lo sono e corrispondono alle convenzioni (costanti che iniziano con una lettera maiuscola, ecc.), È già chiaro dove il tipo di elementi si interrompe e altri iniziano, quindi non è necessario creare esplicitamente regioni per quello.


13
Penso che ci siano almeno alcuni usi difendibili di #regioni - ad es. Il collasso delle clausole di guardia (controllo dei parametri di input) che, se lasciato non colorato, toglie l'essenza o la "carne" del metodo. Un altro esempio è la gestione delle eccezioni sui confini dell'API; spesso non si desidera influire sulla traccia dello stack chiamando altri metodi per racchiudere l'eccezione, quindi sono disponibili diverse righe di codice da racchiudere e ricodificare. Anche questo è spesso un codice non pertinente e può essere tranquillamente compresso.
Daniel B,

9
Controllo di realtà. Ho visto molte #regioni tra metodi che sono state utili. Quando hai un metodo di diverse centinaia di linee con logica di controllo nidificata con dozzine o centinaia di linee con alcune di queste, per fortuna l'idiota ha almeno messo le regioni.
radarbob,

37
@radarbob: in breve, le regioni sono utili nel codice scadente che non dovrebbe esistere in primo luogo.
Arseni Mourzenko,

41
-1 (se avessi la reputazione). Anche se i membri del tuo tipo sono ben organizzati e separati, potrebbero essercene molti. Le regioni ti risparmiano di dover scorrere oltre 10 o 12 proprietà e i getter e setter associati solo per arrivare a un metodo su cui vuoi lavorare. L'unica alternativa è quella di comprimere tutte le tue proprietà individualmente, il che non è qualcosa di cui sono un fan. Le aree di funzionalità mostra / nascondi su larga scala fornite sono estremamente utili. Concordo tuttavia sulle regioni intra-metodo.
Asad Saeeduddin,

14
Non sono assolutamente d'accordo con questa risposta: la puzza di codice e la regione non hanno nulla a che fare l'una con l'altra. Se il tuo codice puzza, puzzerebbe con o senza regioni. Il modo in cui utilizzo le regioni è di separare le mie classi in regioni. In genere mi attengo allo stesso modello: Proprietà pubbliche, Metodi pubblici, Campi privati, Metodi privati. Questo è l'unico uso per cui avrei delle regioni. Nient'altro, probabilmente stai rompendo il principal SRP nel tuo codice.
Alexus,

113

È incredibile per me quante persone odiano le regioni così appassionatamente!

Sono completamente d'accordo con così tante delle loro obiezioni: spingere il codice in un #regionper nasconderlo alla vista è una cosa negativa. Dividere una classe in #regionsquando dovrebbe essere rifattorizzata in classi separate è chiaramente un errore. L'uso di a #regionper incorporare informazioni semantiche ridondanti è, beh, ridondante.

Ma nessuna di queste cose significa che c'è qualcosa di intrinsecamente sbagliato nell'uso delle regioni nel tuo codice! Posso solo supporre che le obiezioni della maggior parte delle persone derivino dal lavorare in team in cui altri sono inclini a utilizzare le funzioni IDE come questa in modo errato. Ho il lusso di lavorare da solo nelle primarie e apprezzo il modo in cui le regioni hanno contribuito a organizzare il mio flusso di lavoro. Forse è il mio disturbo ossessivo compulsivo, ma non mi piace vedere un sacco di codice alla volta sul mio schermo, non importa quanto possa essere pulito ed elegantemente scritto. Separare le cose in aree logiche mi permette di comprimere il codice che non mi interessa lavorare sul codice che facciopreoccupati. Non sto ignorando il codice scritto male, non ha senso riformattarlo più di quanto non sia, e l'organizzazione "meta" aggiuntiva è descrittiva, piuttosto che inutile.

Ora che ho trascorso più tempo a lavorare in C ++, programmando più direttamente sull'API di Windows, mi ritrovo a desiderare che il supporto per le regioni fosse buono come lo è per C #. Si potrebbe sostenere che l'uso di una libreria GUI alternativa renderebbe il mio codice più semplice o più chiaro, eliminando così la necessità di ottenere rumori di codice irrilevanti dallo schermo, ma ho altri motivi per non voler farlo. Sono abbastanza abile con la mia tastiera e IDE che l'espansione / compressione del codice suddiviso in regioni richiede meno di una frazione di secondo. Il tempo che risparmio in termini di capacità cerebrale, cercando di limitare la mia attenzione cosciente solo al codice su cui sto attualmente lavorando, è più che valsa la pena. Appartiene tutto in una singola classe / file, ma non tutti appartengono contemporaneamente al mio schermo.

Il punto è che l'utilizzo #regionsper separare e dividere logicamente il codice non è una cosa negativa da evitare a tutti i costi. Come sottolinea Ed, non è un "odore di codice". Se il tuo codice ha un odore, puoi essere sicuro che non provenga dalle regioni, ma invece da qualunque codice tu abbia tentato di seppellire in quelle regioni. Se una funzione ti aiuta a essere più organizzata o a scrivere un codice migliore, allora dico di usarla . Se diventa un ostacolo o ti ritrovi a usarlo in modo errato, allora smetti di usarlo. Se il peggio viene al peggio e sei costretto a lavorare in una squadra con persone che lo usano, allora memorizza la scorciatoia da tastiera per disattivare la definizione del codice: Ctrl+ M, Ctrl+P. E smettila di lamentarti. A volte ho la sensazione che questo sia un altro modo in cui coloro che vogliono essere visti come programmatori "veri", "hardcore" amano provare a mettersi alla prova. Evitare le regioni è meglio che evitare la colorazione della sintassi. Non ti rende uno sviluppatore più macho.

Detto questo, le regioni all'interno di un metodo sono solo assurdità. Ogni volta che ti ritrovi a voler farlo, dovresti eseguire il refactoring in un metodo separato. Niente scuse.


9
Ben detto. L'uso delle regioni per l'organizzazione non è più dannoso della commutazione dell'opzione "Visualizza spazi bianchi" dell'IDE. È una preferenza personale.
Josh

24
Lavorando su WPF con ViewModels che hanno 10 o 20 proprietà che semplicemente racchiudono le proprietà sul mio modello, adoro le regioni: posso semplicemente nascondere quelle proprietà in una regione (non devono mai essere toccate) e tenere gli occhi sul codice pertinente .
Kirk Broadhurst

4
Completamente d'accordo. In .NET 2.0, le proprietà sono lunghe circa 8-10 righe. Quando hai più di 20 proprietà in una classe, occupano molto spazio. Le regioni sono perfette per farle crollare.
Kristof Claes

6
@Kristof: così come le proprietà in .NET 4.0 che eseguono una semplice convalida dell'input. Le proprietà automatiche non sono state poi così magiche per i miei scopi.
Cody Gray

8
Sono disposto a scommettere sulla mia palla sinistra che le persone che odiano le regioni non hanno mai sviluppato un'applicazione WPF o non hanno mai usato le funzionalità di definizione di WPF come l'associazione dati e l'associazione comandi. Basta impostare il codice per fare in modo che il lavoro occupi molto spazio e in genere non è necessario rivederli.
Bangkok,

70

Prima di tutto, non sopporto più il termine "odore di codice". Viene usato troppo spesso ed è spesso utilizzato da persone che non sono in grado di riconoscere un buon codice se lo mordono. In ogni modo ...

Personalmente non mi piace usare molte regioni. Rende più difficile ottenere il codice e il codice è quello che mi interessa. Mi piacciono le regioni quando ho una grande porzione di codice che non ha bisogno di essere toccato molto spesso. A parte questo, sembrano solo intralciarmi e regioni come "Metodi privati", "Metodi pubblici", ecc. Mi fanno impazzire. Sono simili ai commenti della varietà i++ //increment i.

Vorrei anche aggiungere che l'uso delle regioni non può davvero essere un "anti-pattern" in quanto quel termine è comunemente usato per descrivere la logica del programma / modelli di progettazione, non il layout di un editor di testo. Questo è soggettivo; usa ciò che funziona per te. Non finirai mai con un programma non mantenibile a causa del tuo uso eccessivo di regioni, che è ciò che riguarda gli anti-schemi. :)


2
Normalmente ti darei un voto negativo per il commento sull'odore del codice, ma in questo caso è esattamente accurato. Il non codice non può essere un odore di codice. 2!

7
Haha, beh, non intendo dire che il termine "odore di codice" non possa essere usato con precisione. Può, ma in questi giorni la vedo girare così tanto che la mia reazione immediata è solo fastidio, specialmente quando proviene da persone che stanno semplicemente ripetendo ciò che sentono senza capirlo o pensare in modo critico. Dichiarazioni come "più di 5 variabili locali in una funzione sono un odore di codice" mostrano solo la poca esperienza che quella persona ha effettivamente.
Ed S.

13
Non sono sicuro di aver compreso il tuo commento sugli odori del codice. Gli odori di codice non indicano che c'è un problema, ma potrebbe esserci un problema.
Craig

7
+1 per resistere al termine odore di codice. Mi sono stufato quando ho visto un post che sosteneva che i metodi privati ​​erano un odore di codice. Ma nel complesso non sono d'accordo con il tuo disgusto per le regioni. Sono facilmente distratto. In effetti mi piacerebbe che VS avesse una modalità VB4 in cui fosse possibile visualizzare un solo metodo alla volta.
Josh

7
Volevo solo intervenire e dire che l'uso improprio di una metafora perfettamente valida non dovrebbe svalutare la metafora. "Odore di codice" è una grande metafora, che viene immediatamente compresa, facilmente memorizzabile e facilmente utilizzabile. Ci sono ancora molti posti in cui applicare la metafora "odore di codice" è ancora il modo migliore per ottenere un punto.
Eric King,

23

Sì, le regioni hanno un odore di codice!

Sarei felice di vedere le regioni rimosse del tutto dal compilatore. Ogni sviluppatore presenta il proprio schema di toelettatura inutile che non avrà mai valore per un altro programmatore. Ho tutto a che fare con i programmatori che vogliono decorare e abbellire il loro bambino, niente a che fare con alcun valore reale.

Riesci a pensare a un esempio in cui hai pensato "Accidenti, vorrei che il mio collega avesse usato alcune regioni qui!"?

Anche se sono in grado di configurare il mio IDE per espandere automaticamente tutte le regioni, sono ancora irritati e riducono la lettura del codice reale.

Mi dispiacerebbe davvero molto se tutti i miei metodi pubblici fossero raggruppati o meno. Congratulazioni, conosci la differenza tra una dichiarazione variabile e l'inizializzazione, non è necessario visualizzarla nel codice!

Toelettatura senza valore!

Inoltre, se il tuo file ha bisogno di "architettura dell'informazione" attraverso l'uso di regioni, potresti voler combattere il problema principale: la tua classe è troppo grande! Suddividerlo in parti più piccole è molto più vantaggioso e, se fatto correttamente, aggiunge vera semantica / leggibilità.


#Regions fanno parte del compilatore? Pensavo fossero solo una direttiva per l'IDE che poteva essere ignorata.
Steve Rukuts,

2
Il compilatore dovrebbe ignorarli quando analizza il tuo codice C #. Se non li ignora, vomiterebbe su di loro. Intendo in questo modo.
Joppe,

1
"Riesci a pensare a un esempio in cui hai pensato" Accidenti, vorrei che il mio collega avesse usato alcune regioni qui! "?" Sì, molto. Quando ho una lezione con metodi privati ​​e metodi pubblici, li divido in regioni perché, quando si esegue il refactoring dei metodi pubblici, non è necessario toccare il codice privato e viceversa.
Anshul,

Ovviamente non hai mai visto il codice in outsourcing. Molte volte le regioni sarebbero state fantastiche da vedere nel codice in outsourcing. Anche se il codice fa schifo, almeno sarebbe stato molto più facile capire se fosse stato raggruppato in qualche senso logico. Anche se, se il loro codice non è logico, le regioni non lo sarebbero neanche, quindi probabilmente avrebbe peggiorato le cose. Le regioni sono grandi se usate correttamente però.
Nickmccomb,

15

Personalmente uso le regioni come un modo per raggruppare vari tipi di metodi o parti di codice insieme.

Quindi un file di codice potrebbe apparire così all'apertura:

  • Proprietà pubbliche
  • Costruttori
  • Salva metodi
  • Modifica metodi
  • Metodi di aiuto privati

Non inserisco le regioni nei metodi. IMHO che è un segno di odore di codice. Una volta mi sono imbattuto in un metodo che era lungo oltre 1200 linee e conteneva 5 diverse regioni. È stato uno spettacolo spaventoso!

Se lo stai usando come un modo per organizzare il tuo codice in un modo che consentirà di trovare le cose più velocemente per gli altri sviluppatori, non penso che sia un segno di problemi. Se lo stai usando per nascondere righe di codice all'interno di un metodo, direi che è tempo di ripensare quel metodo.


14
Ugh. So che questo è un argomento soggettivo, ma amico, non riesco proprio a sopportare questo schema. Nella mia esperienza, l '"organizzazione" aggiunta non aiuta affatto e rende la navigazione del codice solo un dolore al collo. Preferisco anche i metodi di raggruppamento non solo per modificatore di accesso ma per responsabilità logica. Per l'interfaccia pubblica in genere raggruppo ogni metodo / proprietà insieme, ma spesso un metodo protetto può chiamare una funzione di supporto privata, e in tal caso preferisco di gran lunga la funzione di supporto (che può essere utilizzata solo lì) per essere sopra o sotto il metodo che lo chiama.
Ed S.

3
@Ed S. - ecco perché ho detto "potrebbe sembrare". È molto soggettivo. Non sto dicendo che ogni file dovrebbe apparire così. Sarei sorpreso se lo facessero. Solo un esempio su un argomento complesso. :)
Tyanna,

Oh lo so, come ho detto; è soggettivo. Qualunque cosa funzioni per te / la tua squadra. L'ho appena fatto per questo schema perché non funziona (per me), ma ho dovuto mantenere un progetto che ha fatto proprio questo. Mi ha fatto impazzire.
Ed S.

3
@EdS. Quindi vai nelle tue opzioni in vs e disattiva le regioni. Problema risolto.
Andy,

Perché i tuoi oggetti hanno metodi di salvataggio? :(
TheCatWhisperer

10

L'uso dei #regionblocchi per rendere leggibile una classe molto ampia è in genere un segnale di violazione del principio di responsabilità singola. Se vengono utilizzati per raggruppare il comportamento, è anche probabile che la classe stia facendo troppo (violando ancora una volta SRP).

Attenendosi alla linea di pensiero "odore di codice", i #regionblocchi non sono odori di codice in sé e per sé, ma invece sono più "Febreze per codice" in quanto cercano di nascondere gli odori. Mentre li ho usati un sacco in passato, mentre inizi a refactoring inizi a vedere meno perché finiscono per non nascondersi molto.


5

La parola chiave qui è "giudiziosa". È difficile immaginare un caso in cui inserire una regione all'interno di un metodo sia giudizioso; è fin troppo probabile che si tratti di nascondere il codice e pigrizia. Tuttavia, ci possono essere buoni motivi per avere alcune regioni qua e là nel proprio codice.

Se ci sono molte e molte regioni, penso che sia un odore di codice. Le regioni sono spesso un suggerimento in un possibile luogo per il futuro refactoring. Molte regioni indicano che qualcuno in realtà non ha mai preso il suggerimento.

Utilizzati con giudizio, forniscono una buona via di mezzo tra la struttura di una singola classe con molti metodi e la struttura di molte classi con solo pochi metodi in ciascuna. Sono molto utili quando una classe inizia ad avvicinarsi al punto in cui dovrebbe essere rifattorizzata in più classi, ma non è ancora del tutto presente. Raggruppando insieme i metodi correlati, faciliterò in seguito l'estrazione di una serie di metodi correlati nella loro classe se continuano a crescere di numero. Ad esempio, se ho una classe che si avvicina a 500 righe di codice, quell'insieme di metodi che utilizza 200 righe di codice totale raccolte insieme in una regione è probabilmente un buon pezzo per refactoring in qualche modo - e quell'altra regione con 100 righe di codice nella sua i metodi potrebbero anche essere un buon obiettivo.

Un altro modo in cui mi piace usare le regioni è ridurre uno degli effetti negativi del refactoring di un metodo di grandi dimensioni: molti metodi piccoli, concisi e facilmente riutilizzabili che un lettore deve scorrere per arrivare a un altro metodo per lo più non correlato. Una regione può essere un bel modo per meta-incapsulare un metodo e i suoi aiutanti per i lettori, quindi qualcuno che sta lavorando con un aspetto diverso della classe può semplicemente comprimerlo e respingere rapidamente quella parte del codice. Ovviamente, questo funziona solo se le tue regioni sono davvero ben organizzate e essenzialmente utilizzate come un altro modo per documentare il tuo codice.

In generale, trovo che le regioni mi aiutino a tenermi organizzata, aiutano a "documentare" il mio codice e mi aiutano a trovare luoghi in cui effettuare il refactoring molto prima che se non uso le regioni.


4

Uso principalmente le regioni per le classi di server CRUD per organizzare i vari tipi di operazioni. Anche allora, potrei andare volentieri senza di loro.

Se usato estesamente, solleverebbe una bandiera rossa. Sarei alla ricerca di lezioni che hanno troppe responsabilità.

Nella mia esperienza, un metodo con centinaia di righe di un codice è sicuramente un odore.


4

La mia regola empirica è: se in un file sono presenti più di 5 regioni, è un odore di codice

Vale a dire, potrebbe andar bene delineare campi, metodi, proprietà e costruttori, ma se stai iniziando a racimolare ogni altro metodo in una sua regione qualcosa è seriamente sbagliato

..e sì, ho partecipato a numerosi progetti in questo caso, spesso a causa di standard di codifica scadenti, generazione di codice o entrambi. È molto vecchio dover attivare o disattivare tutti i contorni in Visual Studio per ottenere una buona panoramica del codice.


4

LE REGIONI HANNO IL LORO UTILIZZO

Li ho usati personalmente per gli eventi dell'interfaccia di "codifica manuale" prima per le app di Windows Form.

Tuttavia nel mio lavoro utilizziamo un generatore di codice per la gestione di SQL e utilizza automaticamente le regioni per ordinare i suoi metodi di selezione, aggiornamento, eliminazione, ecc.

Quindi, anche se non li uso spesso, sono perfettamente adatti per la rimozione di grossi blocchi di codice.


1
Ho usato generatori di codice simili e preferisco usare classi parziali per rimuovere il codice generato.
Craig

Facciamo, le regioni sono all'interno del codice generato per facilitare la lettura o il debug (se necessario).
Ken

4

Se hai il codice IN delle regioni hai sicuramente un problema (escluso il caso del codice generato). Mettere le regioni nel codice significa fondamentalmente "refactor this".

Tuttavia, ci sono altri casi. Uno che mi viene in mente che ho fatto un po 'di tempo fa: un tavolo con un paio di migliaia di elementi precalcolati. È una descrizione della geometria, a parte un errore nella tabella non ci sarà mai un'occasione per guardarla. Certo, avrei potuto ottenere i dati da una risorsa o simili, ma ciò escluderebbe l'uso del compilatore per facilitare la lettura.


1
Questo è un caso d'uso migliore per una classe parziale con quella memorizzata in un file separato, o forse un IMyDataSource iniettato con un'implementazione HardcodedDataSource.
Bryan Boettcher,

3

In un recente progetto, esisteva un metodo di linea 1700 con diverse regioni incorporate in esso. La cosa interessante è che le regioni hanno dimostrato azioni distinte che venivano eseguite nell'ambito del metodo. Sono stato in grado di eseguire un refactor -> estrarre il metodo su ciascuna delle regioni senza influire sulla funzionalità del codice.

In generale, le regioni utilizzate per nascondere il codice della piastra della caldaia sono utili. Vorrei sconsigliare l'uso delle regioni per nascondere proprietà, campi e simili perché se sono troppo ingombranti da guardare quando si lavora all'interno della classe, è probabilmente un segno che la classe dovrebbe essere ulteriormente suddivisa. Ma come regola difficile, se stai inserendo una regione all'interno di un metodo, probabilmente staresti meglio estraendo un altro metodo che spiega cosa sta succedendo che avvolgere quel blocco in una regione.


3

Le regioni possono essere utilizzate in codice di buona qualità? Probabilmente. Scommetto che lo sono, in molti casi. Tuttavia, la mia esperienza personale mi lascia molto sospettoso: ho visto le regioni utilizzate quasi esclusivamente. Direi che sono sfinito, ma comunque ottimista.

Posso dividere approssimativamente il codice che utilizza la regione che ho visto finora in tre categorie:

  • Codice scarsamente fattorizzato: la maggior parte del codice che ho visto utilizza le regioni come strumento di factoring per poveri. Ad esempio, una classe che è cresciuta fino al punto in cui ha senso specializzarla per scopi diversi potrebbe invece essere suddivisa in regioni separate, una per ogni scopo.

  • Codice scritto usando le librerie sbagliate, e talvolta la lingua sbagliata, per il dominio problematico Spesso, quando un programmatore non utilizza il giusto set di librerie per il dominio problematico, vedrai il codice diventare incredibilmente dettagliato - con molte piccole funzioni di supporto che in realtà non appartengono (probabilmente appartengono alla propria biblioteca).

  • Codice scritto da studenti o neolaureati. Alcuni programmi e corsi sembrano tentare di inculcare gli studenti con l'uso delle regioni per tutti i tipi di scopi strani. Vedrai le regioni disseminate di codice sorgente al punto in cui il rapporto tra i tag di regione e le righe di codice è compreso nell'intervallo 1: 5 o peggio.


3

Direi che è un "odore di codice".

Gli anti-pattern sono generalmente problemi strutturali fondamentali in un pezzo di software, mentre le regioni, da sole, causano un comportamento odioso in un editor. L'uso delle regioni non è in realtà intrinsecamente negativo, ma usarle molto, soprattutto per nascondere blocchi di codice, può indicare che ci sono altri problemi indipendenti e maggiori che stanno accadendo altrove.


@Andrew Grimm: sì
whatsisname

3

Uso le regioni solo per una cosa (almeno non riesco a pensare ad altri posti in cui le uso): raggruppare i test unitari per un metodo.

Di solito ho una classe di test per classe e quindi raggruppo i test unitari per ciascun metodo usando le regioni che hanno il nome del metodo. Non sono sicuro che si tratti di un odore di codice o altro, ma poiché l'idea di base è che i test unitari non devono cambiare a meno che non si rompano perché qualcosa nel codice è cambiato, mi rende più facile trovare tutti i test per un metodo specifico abbastanza rapidamente.

Potrei aver usato le regioni per organizzare il codice in passato, ma non ricordo l'ultima volta che l'ho fatto. Mi attengo alle mie regioni nelle classi di unit test.


1
Hai mai avuto test che testano più di un metodo?
Marcie

Non capisco davvero la domanda o ciò che stai mirando. La risposta è: No, un test unitario è sempre mirato a un solo metodo o piuttosto a un determinato aspetto di un metodo.
Anne Schuessler il

2

Credo che siano un modello anti e francamente penso che dovrebbero essere eliminati. Ma se ti trovi nella sfortunata situazione di lavoro in un posto in cui sono uno standard Visual Studio offre uno strumento fantastico per ridurre al minimo la quantità che vorresti vomitare ogni volta che vedi una regione I Hate #Regions

Questo plugin aumenterà al massimo la dimensione del carattere delle regioni molto piccole. Verranno inoltre espansi, quindi non dovrai premere ctr + m + l per aprire tutte le regioni. Non risolve questa forma di cancro del codice ma lo rende sopportabile.


0

Uso le regioni per contenere ogni combinazione di visibilità e tipo di membro. Quindi tutte le funzioni private vanno in una regione, ecc.

Il motivo per cui lo faccio non è così posso ripiegare il codice. È perché ho il mio editor scritto in modo da poter inserire, per esempio, un riferimento a un proxy:

#region "private_static_members"
 /// <summary>
 /// cache for LauncherProxy
 /// </summary>
private static LauncherProxy _launcherProxy;
#endregion

#region "protected_const_properties"
protected LauncherProxy LauncherProxy{
  get{
    if(_launcherProxy==null) {
      if (!God.Iam.HasProxy(LauncherProxy.NAME)) {
        God.Iam.RegisterProxy(new LauncherProxy());
      }
      _launcherProxy=God.Iam.Proxy(LauncherProxy.NAME) as LauncherProxy;
    }
    return _launcherProxy;
  }
}
#endregion

nel codice e avere ogni parte ordinatamente inserita nella regione corretta.

In questo caso la macro analizzerebbe il mio progetto, mi darebbe una casella di riepilogo di proxy e inietterebbe il codice per quello che desidero. Il mio cursore non si muove nemmeno.

All'inizio dell'apprendimento di C # avevo considerato l'uso delle regioni per mantenere insieme la comunanza, ma questa è una proposta incostante perché non è una relazione uno a uno in ogni momento. Chi vuole agitarsi per un membro utilizzato da due regioni, o addirittura iniziare a rompere le cose a quei termini.

L'unico altro tipo di segregazione sono i metodi: suddividerò i metodi in Comandi, Funzioni e Gestori, quindi avrei una regione per Comandi pubblici, privati, ecc., Ecc.

Questo mi dà granularità, ma è una granularità coerente e inequivocabile su cui posso contare.


-1 non appena ottengo 125 punti da sottovalutare. Stai aggiungendo righe di codice non necessarie. PERCHÉ PERCHÉ Metterei una regione attorno a una proprietà ... if (God.Iam.AbusingRegions () == true) myName = "Mark"
DeadlyChambers

1
@DeadlyChambers Il motivo è indicato nel secondo paragrafo: sto usando macro di editor per iniettare schemi di codice comuni nel file, le regioni aiutano a mantenere il file strutturato in modo da raggruppare elementi simili. Non sto inserendo una regione attorno a una proprietà singolare, ma tutte le proprietà rientrano in una regione designata in base ai loro attributi "protected_const_properties". Hai letto il post??
Segna il

1
Probabilmente puoi trasformarlo in: protetto LauncherProxy LauncherProxy => God.Iam.GetOrAddProxy <LauncherProxy> (ref _launcherProxy); e quindi ora non hai bisogno della regione. Inoltre _launcherProxy può essere rinominato in _launcherProxyCache in modo da non aver bisogno di regione o commenti lì.
aeroson

0

Le regioni sono espressioni del preprocessore - in altre parole sono trattate come commenti e sostanzialmente ignorate dal compilatore. Sono puramente uno strumento visivo utilizzato in Visual Studio. Pertanto #region non è in realtà un odore di codice, perché non è semplicemente codice. L'odore di codice è piuttosto il metodo a 800 righe che ha molte responsabilità diverse incorporate ecc. Quindi, se vedi 10 regioni in un metodo, è probabilmente usato per nascondere un odore di codice. Detto questo, li ho visti usati in modo estremamente efficace per rendere una lezione più piacevole alla vista e più navigabile, anche in una classe ben scritta e strutturata!


0

Le regioni erano un'idea organizzativa elegante, ma non sono state prese in considerazione alcune tendenze degli sviluppatori di voler sovra-categorizzare tutto, e generalmente inutili secondo la maggior parte delle pratiche OOP dei giorni nostri ... sono un "odore", nel senso che il loro uso spesso indica che la tua classe / metodo è troppo grande e dovrebbe essere riformulato, poiché probabilmente stai violando la "S" dei principi SOLIDI ... ma come ogni odore, non significa necessariamente che qualcosa stia andando male.

Le regioni servono più allo scopo nel codice funzionale piuttosto che nel codice orientato agli oggetti, IMO, dove hai lunghe funzioni di dati sequenziali che ha senso rompere, ma ci sono state volte in cui le ho usate personalmente in c #, e quasi sempre concentrarsi sul codice che non è necessario / che si desidera guardare. Per me, queste erano di solito costanti di stringa SQL non elaborate nella base di codice utilizzata per NPoco o le sue varianti. A meno che non ti interessi davvero come arrivano i dati per compilare l'oggetto POCO attraverso il tuo ORM, questi erano completamente inutili da guardare ... e se ti importava, ehi, basta espandere la regione e BAM! Più di 150 righe di alcune query SQL complicate per il tuo piacere di visione.

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.