È comune utilizzare classi parziali per ottenere la "modularità"?


24

Di recente ho riscontrato una situazione nella nostra base di codice in cui un team diverso ha creato una "classe divina" contenente circa 800 metodi, suddivisa in 135 file come classe parziale.

Ho chiesto all'altra squadra di questo. Mentre la mia reazione istintiva è stata quella di liberarlo dall'orbita, insistono sul fatto che sia un buon design, una pratica comune e che promuova la "modularità" e la "facilità di implementazione" perché i nuovi sviluppatori possono sfruttare la funzionalità quasi senza alcuna conoscenza del resto del sistema.

È davvero una pratica comune o in qualche modo una buona idea? Sono propenso a prendere provvedimenti immediati per abbattere questa bestia (o almeno impedire che cresca ulteriormente) ma sono disposto a credere di sbagliarmi.


6
uccidilo col fuoco! Ma sul serio, l'altra squadra può fornire citazioni per questa presunta pratica comune?
MattDavey,

1
Nessuna. Sono sicuro che stanno soffiando fumo ma sto cercando di fare la mia dovuta diligenza prima di lasciar cadere il martello.
Joshua Smith,

Qual è il loro ragionamento per non farlo sempre?
JeffO

3
Chiedi loro di descrivere, in una frase, cosa hanno in comune gli 800 metodi tra 135 file. Dovrebbe essere possibile rispondere a ciò per qualsiasi classe sana e ragionevole.
Carson63000,

3
@ Carson63000 "Esegue tutte le funzioni richieste del progetto." c'è la tua unica frase.
Ryathal,

Risposte:


39

Questa non è in alcun modo una buona idea.

Esistono classi parziali per aiutare il progettista di moduli. Usarli per qualsiasi altra ragione (e probabilmente per lo scopo previsto, ma è una questione diversa) è una cattiva idea, perché porta a classi gonfie che sono difficili da leggere e comprendere.

Guardalo in questo modo: se una classe divina con 800 metodi in un unico file, dove sai dove si trova tutto, è una cosa negativa - e penso che tutti sarebbero d'accordo che sia - allora come può una classe divina con 800 metodi distribuito su 135 file, dove non sai dove tutto può essere una buona cosa?


1
Sono principalmente d'accordo, ma penso che ci possano essere alcuni rari casi in cui partialpuò essere utile anche senza codice generato. Forse quando hai qualcosa come una classe nidificata?
svick

1
@svick: le lezioni parziali sono interessanti, ma di solito non sono necessarie. Non sono sicuro del perché dividere una classe in file separati sarebbe utile quando ci sono classi nidificate. A meno che non si desideri la classe nidificata nel proprio file fisico. In quel caso ... maay , va bene. ;)
FrustratedWithFormsDesigner

5
A volte uso classi parziali per implementazioni esplicite dell'interfaccia, in particolare qualcosa come System.IConvertible. In qualche modo sembra più pulito di mettere una grande regione nella mia classe.
MattDavey,

1
Il commento della classe nidificata è in realtà una buona idea, non ci avevo nemmeno pensato. Anche se ... ciò ha più a che fare con l'organizzazione, che con la "modularità"
Sheldon Warkentin,

1
"Esistono classi parziali per aiutare il progettista di moduli." Corretto in generale, ma aggiungerei "... e altri generatori di codice.". Accetto il resto della tua risposta;)
Silas,

14

Quindi la domanda era:

È davvero una pratica comune o in qualche modo una buona idea?

Tra le risposte attualmente disponibili c'è un clamoroso no . Quindi ci sono poche altre cose su cui potrei parlare, come ad esempio; anche il codice procedurale può essere reso modulare e includere tutto tranne il lavello della cucina non è il modo in cui si ottiene la modularità. Ciò che fa una classe gigante divisa in parziali, tutto si somma in un grande casino.

Tuttavia, questa domanda è un'aringa rossa per la vera parte critica di ciò che è stato perso; poiché l'OP ha anche le seguenti affermazioni sulla situazione:

(...) Mentre la mia reazione istintiva era quella di liberarlo dall'orbita, insistono ...

(...) Sono propenso a prendere provvedimenti immediati per abbattere questa bestia (o almeno impedire che cresca ulteriormente) ma sono disposto a credere di sbagliarmi.

Tieni i tuoi cavalli!

Questo qui è qualcosa che farebbe cadere il mio monocolo in senso figurato nella mia tazza di tè figurativa.

Sono stato in situazioni simili e lascia che te lo dica: NON cadere per l'impulso di farlo. Certo, puoi far cadere Nuke Hammer of Justice nella squadra, ma prima di farlo per favore umorizza te stesso con il seguente enigma:

Cosa succederà se dirai alla squadra che il loro codice fa schifo e si esaurisce ?

(... o qualcosa del genere, ma in modo meno offensivo, non importa perché saranno offesi indipendentemente da ciò che fai se decidi di metterli in pratica)

Qual è la situazione attuale con la base di codice? Funziona? Quindi avrai grossi problemi a spiegare ai loro clienti che il loro codice essenzialmente fa schifo . Indipendentemente dalle ragioni che hanno: finché funziona, la maggior parte dei client non si preoccupa di come è organizzato il codice.

Mettiti anche nei loro panni, cosa farebbero? Lascia che ti diverta con il seguente esito molto possibile:

Membro del team n. 1: "Quindi c'è questo ragazzo che ci dice che abbiamo fatto qualcosa di sbagliato negli ultimi anni."

Membro del team n. 2 e n. 3: "Che idiota."

Membro influente del team n. 4: "Non ti preoccupare, andrò alla direzione e lo riferirò come una minaccia."

Vedi cosa ha fatto il membro influente del team n. 4 lì? È andato alla direzione e ha ridotto il tuo karma in compagnia. Potrebbe essere italiano-americano, dicendo a tutti di non preoccuparsene, ma poi sarei razzista.

Dipingere la squadra che ha commesso il fallo in un angolo lasciando che ammettessero di aver sbagliato per così tanto tempo è anche una cattiva idea e portare alla stessa cosa. Perderai rispetto e un po 'di karma politico d'ufficio.

Anche se sei riuscito a convincere un gruppo di persone a firmare questo, al fine di "insegnare una lezione al team", ricorda che lo stai facendo a persone abbastanza intelligenti che apparentemente fanno qualcosa. Una volta che il codice verrà riscritto / refactored / trattato / qualunque cosa si verifichi e sorgono problemi che sarai ritenuto responsabile come se fossi il più importante .

Essere avversari in situazioni come questa è per lo più una partita persa / persa in quanto rischia di diventare un circolo vizioso di giochi di colpa. Questo è un risultato non ottimale per questa situazione. Anche se vinci, ti viene improvvisamente consegnato il casino che qualcun altro ha fatto.

Ci sono altri modi (molto maturi)

Una volta mi trovavo in una situazione simile, ma poi ho preso una freccia nel ginocchio. Quindi, dopo un po 'con quell'improvvisa carriera che ha cambiato la freccia nella mia mente, ho avuto un libro Driving Technical Change di Terrence Ryan . Elenca diversi schemi di scettici, il tipo di persone che non agisce su buone idee. Molto probabilmente sono applicabili nel caso del PO:

  • The Uninformed - Davvero non sapevano che c'erano altri modi o semplicemente non capivano. Gli sviluppatori junior di solito rientrano in questa categoria ma non necessariamente. (Ad essere sincero: ho incontrato sviluppatori junior che sarebbero stati più brillanti di così.)
  • The Herd - Conoscevano tecniche migliori rispetto all'utilizzo di classi parziali ma non sapevano che erano ammessi.
  • The Cynic - A loro piace semplicemente sostenere che avere lezioni parziali è meglio della tua idea solo per il gusto di discutere. È facile farlo in mezzo alla folla invece di stare di fronte a una folla.
  • The Burned - Per qualche strana ragione non gli piace creare nuove classi, molto probabilmente lo percepiscono come troppo difficile.
  • The Time Crunched - Sono così occupati che non possono preoccuparsi di correggere il loro codice.
  • The Boss - Pensano: "Beh, funziona; quindi perché preoccuparsi?"
  • The Irrational - Ok, sono completamente pazzi.

Il libro continua con un elenco di strategie e così via, ma nel caso del PO è una questione di persuasione. Andare forte con i fatti sull'anti-schema non è abbastanza.

Se è nel tuo interesse aumentare la qualità del codice, almeno dai al team che ti ha offeso la possibilità di reiterare e correggere il proprio pasticcio . Personalmente proverei a influenzarli ascoltando e ponendo domande importanti, lasciando che raccontino la loro storia:

  • Cosa sta facendo esattamente la loro classe di dio?
  • Hanno riscontrato problemi? Hanno qualche bug? Suggerisci correzioni sane senza dire loro di farlo.
  • Se sei un utente di questa divina classe come API: ci sono modi più semplici di usare il codice che di usare tutto? Suggerisci esempi più semplici, guarda come reagiscono.
  • Puoi cambiare alcune funzionalità con un'altra, senza dover scrivere la funzione?
  • Hanno bisogno di un po 'di allenamento? Riesci a convincere il management a darglielo o a pranzare su schemi e pratiche?

... e così via. Dai loro piccoli suggerimenti in modo che possano andare avanti. Ci vuole tempo e avrà bisogno di un po 'di grasso per i gomiti di livello politico, ma la pazienza e il duro lavoro sono una virtù, giusto?


Questa è una risposta molto perspicace. Se sei un nuovo sviluppatore, devi capirlo. Gli sviluppatori più esperti se ne rendono conto dopo diversi anni, alcuni non lo fanno mai.
Fishy:

6

La pagina Classi e metodi MSDN parziali suggerisce due situazioni per l'utilizzo di classi parziali:
1. Per dividere una classe gigante in più file separati.
2. Avere un posto dove mettere il codice sorgente generato automaticamente.

2 è molto utilizzato da Visual Studio (ad es. Per file aspx e per winforms). Questo è un uso ragionevole di classi parziali.

1 è quello che sta facendo la tua squadra. Direi che l'uso di classi parziali è un modo perfettamente ragionevole per ottenere la modularità quando si hanno classi giganti, ma avere classi giganti è di per sé irragionevole. In altre parole, avere una classe gigante è una cattiva idea, ma se hai intenzione di avere una classe gigante, le classi parziali sono una buona idea.

Tuttavia, se puoi dividere in modo intelligente una classe in file separati su cui diversi utenti possono lavorare, non puoi semplicemente dividerla in classi separate?


+1 per "non puoi semplicemente dividerlo in classi separate invece?". Questo è esattamente ciò che stiamo suggerendo. Sembra buon senso che avrebbe dovuto essere fatto in quel modo in origine.
Joshua Smith,

4

Quindi, alla fine, stanno facendo un normale sviluppo procedurale senza alcuna parte di OOP. Hanno uno spazio dei nomi globale con tutti i metodi, le variabili e quant'altro.

O convincerli che stanno sbagliando o tirano fuori di lì.


1

Una classe di utilità contiene metodi che non possono essere sensibilmente combinati con altri metodi per creare una classe. Se hai più di 800 metodi, suddivisi in 135 file, sembra che qualcuno sia riuscito a trovare alcuni metodi comuni ...

Solo perché hai una classe di utilità, non significa che non puoi avere un'altra classe di utilità.

Anche se hai 800 metodi per lo più non correlati, la soluzione non è una grande classe e molti file. La soluzione è uno spazio dei nomi, alcuni spazi dei nomi secondari e molte piccole classi. Questo è un po 'più di lavoro (devi trovare un nome per la classe e il metodo). Ma ti renderà la vita più facile quando arriverà il momento di ripulire questo pasticcio, e nel frattempo renderà l'intellisense più facile da usare (cioè più facile scoprire dove un metodo deve usarlo).

E no, questo non è comune (più il numero di file che il numero di funzioni gratuite).


0

Non mi piace per niente. Tuttavia, forse le classi parziali hanno avuto senso per gli sviluppatori durante lo sviluppo perché hanno consentito lo sviluppo simultaneo di questo gran numero di metodi, specialmente se non c'è molta dipendenza tra di loro.

Un'altra possibilità è che quelle classi parziali siano state costruite per modificare una classe principale generata automaticamente. In tal caso, non è necessario toccarli, altrimenti il ​​codice personalizzato verrebbe emesso durante la rigenerazione.

Non sono sicuro che qualcuno possa mantenerlo facilmente senza qualche studio. Ora se lo uccidi, il numero di metodi non diminuirà. Il numero di metodi e complessità, per me, è il vero problema. Se i metodi appartengono davvero alla classe, quindi avere 1 file enorme non ti semplifica la vita, specialmente in manutenzione, infatti, potrebbe essere più soggetto a errori esporre tutto questo codice per errori sciocchi come la ricerca di caratteri jolly e sostituisci.

Quindi fai attenzione e giustifica la decisione di uccidere. Inoltre, considera quali test saranno richiesti.


0

Va benissimo dal punto di vista della progettazione pratica assumendo che i 135 file raggruppino effettivamente metodi simili a quelli che farebbero le classi tradizionali. È solo una media di 6 metodi per file. Non è sicuramente il modo più popolare o tradizionale di progettare un progetto. Cercare di cambiarlo creerà solo un sacco di problemi e cattiva volontà senza alcun beneficio reale. Rendere il progetto conforme agli standard OO creerà tutti i problemi che risolve. È una questione completamente diversa se i file multipli non forniscono effettivamente separazioni significative.


3
Rifattorizzare il codice procedurale in OO in genere ha questo problema: penso che risolvere questo sarà un compito enorme e insegnare al team a codificare correttamente anche più in fretta, inoltre Joshua sarà incolpato di tutto ciò che succederà nel prossimo anno (e oltre ) se li convince a refactoring. Questo è il motivo per cui nessuno ha mai spinto troppo per fare i refactor in questo modo (almeno non dopo aver visto i risultati). Anche se pensi che sia un bel design - beh - rivisita questa risposta in 5 anni e facci sapere cosa ne pensi allora (sembra che riapprenda tutto ciò che so sul design ogni 5 anni circa).
Bill K,

@BillK se aspetti dieci anni quello che sai sarà probabilmente l'attuale filosofia del design "in".
Ryathal,

I 135 file generalmente raggruppano metodi correlati, ma ciò (per me) non lo rende ancora una buona idea. Voglio mettere alla prova questo sistema ma stub / deridere l'idra a 800 metodi sarà un brutto dolore nel culo.
Joshua Smith,

@Ryathal non è ciò che è "in", è quello che pensi sia un buon design (per buoni motivi) e poi, mentre pratichi e migliora, ti rendi conto che non è proprio un'idea buona come pensavi. Sembra che succeda ogni 5 anni circa, e una volta che ho riconosciuto che è la moderazione della mia risposta ai commenti di alcune persone perché mi rendo conto che in realtà sono designer eccellenti che sono (come tutti noi) in procinto di migliorare per sempre le nostre pratiche. L'unico programmatore di cui mi preoccuperei è uno che non pensava di poter migliorare il codice che avevano scritto 5 anni fa.
Bill K,

0

Oltre alle risposte già evidenziate, le classi parziali possono essere utili in un progetto a più livelli in cui si desidera organizzare funzionalità che tagliano trasversalmente la gerarchia delle classi in file separati specifici per livello. Ciò consente di utilizzare Esplora soluzioni per navigare tra le funzionalità per livello (per organizzazione dei file) e la vista di classe per navigare tra le funzionalità per classe. Preferirei usare un linguaggio che supporti mixin e / o tratti, ma le classi parziali sono un'alternativa ragionevole se usate con parsimonia, e non dovrebbero sostituire una buona progettazione della gerarchia di classi.

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.