it-swarm.it

C'è qualcosa come avere troppe funzioni / metodi privati?

Comprendo l'importanza di un codice ben documentato. Ma capisco anche l'importanza del codice autocompensante . Più è facile leggere visivamente una particolare funzione, più velocemente possiamo passare durante la manutenzione del software.

Detto questo, mi piace separare funzioni grandi in altre più piccole. Ma lo faccio fino al punto in cui una classe può averne fino a cinque solo per servire un metodo pubblico. Ora moltiplica cinque metodi privati ​​per cinque metodi pubblici e otterrai circa venticinque metodi nascosti che probabilmente verranno chiamati solo una volta da quei metodi 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]

La gente mi ha chiesto perché penso che avere troppe funzioni sia una cattiva pratica.

La semplice risposta: è una sensazione viscerale.

La mia convinzione non è, per un po ', supportata da nessuna 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 programmato solo progetti personali. È solo di recente che sono passato a progetti basati su team. Ora voglio assicurarmi che gli altri possano leggere e comprendere il mio codice.

Non ero sicuro di cosa migliorerà 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 è solo ridondante.

Quindi, sto chiedendo questo per illuminarmi per scegliere la strada giusta.

[Edit]

Di seguito, ho incluso due versioni di come potrei risolvere il mio problema. Il primo risolve risolvendo non la separazione di grossi blocchi di codice. Il secondo separa le cose.

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 per tutto il tempo di esecuzione del programma.

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

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

63
Sal

Ora moltiplica cinque metodi privati ​​per cinque metodi pubblici e otterrai circa venticinque metodi nascosti che probabilmente verranno chiamati solo una volta da quei metodi pubblici.

Questo è ciò che è noto come Encapsulation , che crea un Control Abstraction al livello superiore. Questa è una buona cosa.

Ciò 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 complesse, piccole, che devono essere eseguite per facilitare la funzione molto più ampia e astratta di startTheEngine().

A meno che il problema che stai affrontando nel tuo codice non riguardi direttamente uno di questi componenti, i manutentori del codice possono andare avanti, ignorando la funzionalità sandbox e incapsulata.

Ciò ha anche l'ulteriore vantaggio 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. Improvvisamente, i tuoi manutentori stanno solo guardando l'astrazione invece di essere in grado di scavare in componenti misurabili.

Il mio consiglio è di continuare a fare ciò che state facendo man mano che il vostro codice si ridimensionerà, sarà facile da mantenere e potrà essere utilizzato e aggiornato per gli anni a venire.

36
jmort253

Sì e no. Il principio fondamentale è: n metodo dovrebbe fare solo una cosa e una cosa

È corretto "suddividere" il metodo in metodi più piccoli. Inoltre, questi metodi dovrebbero essere in modo ottimale abbastanza generale da non solo servire quel metodo "grande" ma essere riutilizzabili in altri luoghi. In alcuni casi, tuttavia, un metodo seguirà una struttura ad albero semplice, come un metodo Initialize che chiama InitializePlugins, InitializeInterface ecc.

Se hai un metodo/classe davvero grande, di solito è un segno che sta facendo molto e devi fare un po 'di refactoring per rompere il "blob". Perphaps nasconde una certa complessità in un'altra classe sotto un'astrazione e usa l'iniezione di dipendenza

22
Homde

Penso che in generale sia meglio sbagliare dal lato di troppe funzioni anziché di 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 utilizzare 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 usata una sola volta se aggiunge leggibilità e manutenibilità.

17
Karl Bielefeldt

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

Avere molti piccoli metodi privati ​​non è una brutta cosa, ma presta attenzione a quella sensazione assillante che ti sta facendo pubblicare una domanda qui :). Se arrivi a un punto in cui stai scrivendo 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.

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

10
Pete Hodgson

Quasi ogni OO che abbia mai aderito ha sofferto molto per le classi troppo grandi e per i metodi troppo lunghi.

Quando sento la necessità di un commento che spieghi la prossima sezione di codice, quindi estraggo quella sezione in un metodo separato. A lungo termine, questo rende il codice più breve. Quei piccoli metodi vengono riutilizzati più di quanto ti aspetteresti inizialmente. Inizi a vedere opportunità per raccoglierne un gruppo in una classe separata. Presto stai pensando al tuo problema ad un livello superiore e l'intero sforzo va molto più veloce. Le nuove funzionalità sono più facili da scrivere, perché puoi basarti su quelle piccole classi che hai creato da quei piccoli metodi.

8
kevin cline

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 in modo "doSomethingPart1", "doSomethingPart2". Non ottieni nulla se quei metodi privati ​​sono solo pezzi di una lunga storia arbitrariamente divisa, ognuno dei quali è insignificante al di fuori dell'intero contesto.

7
user281377

Estratto da R. Martin's Clean Code (p. 176):

Anche concetti fondamentali come l'eliminazione della duplicazione, l'espressività del codice e l'SRP possono essere portati troppo lontano. Nel tentativo di ridurre le nostre classi e metodi, potremmo creare troppe piccole classi e metodi. Quindi questa regola [minimizza il numero di classi e metodi] suggerisce che manteniamo bassi anche i nostri conteggi di funzioni e classi. Conteggi di classe e metodi elevati sono talvolta il risultato di un dogmatismo inutile.

4
user2418306

Alcune opzioni:

  1. Va bene. Basta nominare i metodi privati ​​e nominare i metodi pubblici. E dai un nome ai tuoi metodi pubblici.

  2. Estrarre alcuni di questi metodi di supporto in classi di aiuto o moduli di supporto. E assicurati che queste classi/moduli di supporto abbiano un buon nome e siano solide astrazioni in sé e per sé.

3
yfeldblum

Non credo che ci sia mai un problema di "troppi metodi privati" se si sente in questo modo probabilmente è un sintomo di scarsa architettura del codice.

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

Se il problema è che aprendo la tua classe, è pieno di metodi privati ​​che stanno dividendo blocchi più grandi in blocchi di codice più piccoli, allora 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'argomento contrario di questo è il detto che un programmatore junior può mettere a soqquadro la soluzione in 50 righe di codice che impiega un architetto in 50 classi.

1
Michael Shaw

C'è qualcosa come avere troppe funzioni/metodi privati?

Sì.

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

C'è una convenzione di denominazione "una specie di privato", ma il gioco è fatto.

Privato può portare a codici difficili da testare. Può anche infrangere il "Principio aperto-chiuso" rendendo il codice semplicemente chiuso.

Di conseguenza, per le persone che hanno usato Python, le funzioni private non hanno alcun valore. Rendi tutto pubblico e falla finita.

0
S.Lott