Esiste troppe funzioni / metodi privati?

61

Capisco l'importanza di un codice ben documentato. Ma capisco anche l'importanza del codice auto-documentante . Più è facile leggere visivamente una determinata funzione, più velocemente possiamo andare avanti durante la manutenzione del software.

Detto ciò, mi piace separare le funzioni big in altre più piccole. Ma lo faccio a un punto in cui una classe può avere più di cinque di loro solo per servire un metodo pubblico. Ora moltiplica cinque metodi privati di cinque di quelli pubblici e ottieni circa venticinque metodi nascosti che probabilmente verranno chiamati solo una volta da quelli pubblici.

Certo, ora è più facile leggere quei metodi pubblici, ma non posso fare a meno di pensare che avere troppe funzioni sia una cattiva pratica.

[Edit]

Le persone mi hanno chiesto perché penso che avere troppe funzioni sia una cattiva pratica.

La risposta semplice: è una sensazione istintiva.

La mia convinzione non è, per un certo punto, sostenuta da alcuna ora di esperienza di ingegneria del software. È solo un'incertezza che mi ha dato un "blocco dello scrittore", ma per un programmatore.

In passato, ho solo programmato progetti personali. È solo di recente che sono passato a progetti basati sul team. Ora, voglio assicurarmi che gli altri possano leggere e capire il mio codice.

Non ero sicuro di cosa possa migliorare la leggibilità. Da un lato, stavo pensando di separare una grande funzione in altre più piccole con nomi intelligibili. Ma c'era un altro lato di me che diceva che è ridondante.

Quindi, sto chiedendo questo per illuminare me stesso al fine di scegliere il percorso corretto.

[Edit]

Di seguito ho incluso due versioni di come potrei risolvere il mio problema. Il primo lo risolve non separando grandi blocchi di codice. Il secondo fa cose separate.

Prima versione:

public static int Main()
{
    // Displays the menu.
    Console.WriteLine("Pick your option");
    Console.Writeline("[1] Input and display a polynomial");
    Console.WriteLine("[2] Add two polynomials");
    Console.WriteLine("[3] Subtract two polynomials");
    Console.WriteLine("[4] Differentiate two polynomials");
    Console.WriteLine("[0] Quit");
}

Seconda versione:

public static int Main()
{
    DisplayMenu();
}

private static void DisplayMenu()
{
    Console.WriteLine("Pick your option");
    Console.Writeline("[1] Input and display a polynomial");
    Console.WriteLine("[2] Add two polynomials");
    Console.WriteLine("[3] Subtract two polynomials");
    Console.WriteLine("[4] Differentiate two polynomials");
    Console.WriteLine("[0] Quit");
}

Negli esempi precedenti, quest'ultimo chiama una funzione che verrà utilizzata una sola volta nell'intero runtime del programma.

Nota: il codice sopra è generalizzato, ma è della stessa natura del mio problema.

Ora, ecco la mia domanda: quale? Prendo il primo o il secondo?

    
posta skizeey 14.02.2011 - 00:26
fonte

10 risposte

32

Now multiply five private methods by five public ones, and you get around twenty-five hidden methods that are probably going to be called only once by those public ones.

Questo è ciò che è noto come Incapsulamento , che crea un Control Abstraction al livello più alto. Questa è una buona cosa.

Questo significa che chiunque legga il tuo codice, quando arriva al metodo startTheEngine() nel tuo codice, può ignorare tutti i dettagli di livello inferiore come openIgnitionModule() , turnDistributorMotor() , sendSparksToSparkPlugs() , injectFuelIntoCylinders() , activateStarterSolenoid() e tutte le altre funzioni piccole e complesse che devono essere eseguite per facilitare la funzione molto più grande e astratta di startTheEngine() .

A meno che il problema che si sta trattando nel tuo codice non si occupi direttamente di uno di questi componenti, i manutentori del codice possono andare avanti, ignorando la funzionalità incapsulata in modalità sandbox.

Questo ha anche il vantaggio aggiunto di semplificare il test del codice. . Ad esempio, posso scrivere un caso di prova per turnAlternatorMotor(int revolutionRate) e testare la sua funzionalità completamente indipendente dagli altri sistemi. Se c'è un problema con quella funzione e l'output non è quello che mi aspetto, allora so qual è il problema.

Il codice che non è suddiviso in componenti è molto più difficile da testare. All'improvviso, i tuoi manutentori guardano solo all'astrazione invece di essere in grado di scavare in componenti misurabili.

Il mio consiglio è di continuare a fare ciò che stai facendo, in quanto il tuo codice sarà scalabile, facile da mantenere e può essere utilizzato e aggiornato per gli anni a venire.

    
risposta data 14.02.2011 - 05:10
fonte
21

Sì e no. Il principio fondamentale è: un metodo dovrebbe fare una cosa e una sola cosa

È corretto "suddividere" il tuo metodo in metodi più piccoli. Quindi, di nuovo, quei metodi dovrebbero essere in generale sufficientemente generici per non solo servire quel "grande" metodo ma essere riusabili in altri posti. In alcuni casi, tuttavia, un metodo seguirà una semplice struttura ad albero, come un metodo di inizializzazione che chiama InitializePlugins, InitializeInterface ecc.

Se hai un metodo / una classe molto grande di solito è un segno che sta facendo molto e hai bisogno di fare qualche refactoring per rompere il "blob". Perphaps nascondono una certa complessità in un'altra classe sotto un'astrazione e usano l'iniezione di dipendenza

    
risposta data 14.02.2011 - 00:40
fonte
16

Penso che in generale sia meglio sbagliare dalla parte di troppe funzioni piuttosto che troppo poche. Le due eccezioni a quella regola che ho visto in pratica sono per DRY e YAGNI principi. Se hai molte funzioni quasi identiche, dovresti combinarle e usare i parametri per evitare di ripetere te stesso. Puoi anche avere troppe funzioni se le hai create "per ogni evenienza" e non vengono utilizzate. Non vedo assolutamente nulla di sbagliato nell'avere una funzione che viene utilizzata una sola volta se aggiunge leggibilità e manutenibilità.

    
risposta data 14.02.2011 - 04:16
fonte
10

La grande risposta di jmort253 mi ha ispirato a dare una risposta "sì, ma" ...

Avere molti piccoli metodi privati non è una brutta cosa, ma prestare attenzione a quel sentimento fastidioso che ti fa postare una domanda qui :). Se arrivi a un punto in cui scrivi dei test focalizzati solo su metodi privati (chiamandoli direttamente o impostando uno scenario in modo tale che uno venga chiamato in un certo modo solo per poter testare il risultato) allora dovresti fare un passo indietro.

Ciò che potresti avere è una nuova classe con la sua interfaccia pubblica più focalizzata che cerca di fuggire. A quel punto potresti voler pensare di estrarre una classe per incapsulare quella parte della tua funzionalità di classi esistenti che attualmente sta vivendo in un metodo privato. Ora la tua classe originale può usare la tua nuova classe come dipendenza e puoi scrivere più test focalizzati su quella classe direttamente.

    
risposta data 14.02.2011 - 09:14
fonte
8

Quasi tutti i progetti OO a cui ho mai partecipato hanno sofferto molto male di classi troppo grandi e di metodi troppo lunghi.

Quando sento la necessità di un commento che spiega la prossima sezione di codice, estraggo quella sezione in un metodo separato. A lungo termine, questo rende il codice più breve. Questi piccoli metodi vengono riutilizzati più di quanto inizialmente ti aspetti. Inizi a vedere le opportunità di raccoglierne un gruppo in una classe separata. Presto penserai al tuo problema ad un livello più alto e l'intero sforzo sarà molto più veloce. Le nuove funzionalità sono più facili da scrivere, perché puoi costruire su quelle piccole classi create da quei piccoli metodi.

    
risposta data 15.02.2011 - 00:09
fonte
7

Una classe con 5 metodi pubblici e 25 metodi privati non mi sembra così grande. Assicurati solo che le tue classi abbiano responsabilità ben definite e non preoccuparti troppo del numero di metodi.

Detto questo, quei metodi privati dovrebbero concentrarsi su un aspetto specifico dell'intera attività, ma non su un modo "doSomethingPart1", "doSomethingPart2". Non ottieni nulla se quei metodi privati sono solo pezzi di una lunga storia arbitrariamente divisa, ognuno privo di significato al di fuori dell'intero contesto.

    
risposta data 14.02.2011 - 10:15
fonte
4

Estratto da Codice pulito di R. Martin (pagina 176):

Even concepts as fundamental as elimination of duplication, code expressiveness, and the SRP can be taken too far. In an effort to make our classes and methods small, we might create too many tiny classes and methods. So this rule [minimize the number of classes and methods] suggests that we also keep our function and class counts low. High class and method counts are sometimes the result of pointless dogmatism.

    
risposta data 02.09.2016 - 18:26
fonte
3

Alcune opzioni:

  1. Va bene. Basta nominare i metodi privati e anche i nomi dei metodi pubblici. E dai il nome ai tuoi metodi pubblici.

  2. Estrarre alcuni di questi metodi di supporto in classi helper o moduli helper. E assicurati che queste classi / moduli di supporto siano ben definiti e rappresentino solide astrazioni di per sé.

risposta data 14.02.2011 - 00:31
fonte
1

Non penso che ci sia mai un problema di "troppi metodi privati" se ritiene che sia probabilmente un sintomo di una scarsa architettura del codice.

Ecco come ci penso ... Se l'architettura è ben progettata, è generalmente ovvio dove dovrebbe essere il codice X. È accettabile se ci sono un paio di eccezioni a questo - ma questi devono essere veramente eccezionali, altrimenti il refactoring dell'architettura per gestirli come standard.

Se il problema è che aprendo la tua classe, è pieno di metodi privati che spezzano pezzi più grandi in blocchi più piccoli di codice, quindi forse questo è un sintomo di architettura mancante. Invece di classi e architettura, quest'area di codice è stata implementata in modo procedurale all'interno di una classe.

Trovare un equilibrio qui dipende dal progetto e dai suoi requisiti. L'argomentazione contraria a questo è il detto che un programmatore junior può far saltare la soluzione in 50 righe di codice che richiede un architetto di 50 classi.

    
risposta data 02.09.2016 - 21:13
fonte
0

Is there such a thing as having too many private functions/methods?

Sì.

In Python il concetto di "privato" (usato da C ++, Java e C #) in realtà non esiste.

Esiste una convenzione di denominazione "tipo-di-privato", ma il gioco è fatto.

Privato può portare a un codice difficile da testare. Può anche infrangere il "principio Open-Closed" rendendo il codice semplicemente chiuso.

Di conseguenza, per le persone che hanno usato Python, le funzioni private non hanno valore. Basta rendere tutto pubblico e fatto con esso.

    
risposta data 14.02.2011 - 12:10
fonte

Leggi altre domande sui tag