È sempre una buona pratica scrivere una funzione per tutto ciò che deve essere ripetuto due volte?

130

Da parte mia, non vedo l'ora di scrivere una funzione quando devo fare qualcosa più di due volte. Ma quando si tratta di cose che appaiono solo due volte, è un po 'più complicato.

Per il codice che richiede più di due righe, scriverò una funzione. Ma di fronte a cose come:

print "Hi, Tom"
print "Hi, Mary"

Sono riluttante a scrivere:

def greeting(name):
    print "Hi, " + name

greeting('Tom')
greeting('Mary')

Il secondo sembra troppo, vero?

Ma cosa succede se abbiamo:

for name in vip_list:
    print name
for name in guest_list:
    print name

Ed ecco l'alternativa:

def print_name(name_list):
    for name in name_list:
        print name

print_name(vip_list)
print_name(guest_list)

Le cose diventano difficili, no? È difficile decidere adesso.

Qual è la tua opinione su questo?

    
posta Zen 13.01.2015 - 05:15
fonte

15 risposte

199

Sebbene sia un fattore decisivo nel decidere di suddividere una funzione, il numero di volte in cui qualcosa viene ripetuto non dovrebbe essere l'unico fattore. Ha spesso senso creare una funzione per qualcosa che viene eseguito solo una volta . In genere, si desidera dividere una funzione quando:

  • Semplifica ogni singolo livello di astrazione.
  • Hai nomi validi e significativi per le funzioni suddivise, quindi di solito non devi saltare tra i livelli di astrazione per capire cosa sta succedendo.

I tuoi esempi non soddisfano questi criteri. Stai andando da una nave singola a una nave singola, e i nomi non ti comprano davvero nulla in termini di chiarezza. Detto questo, le funzioni così semplici sono rare al di fuori dei tutorial e dei compiti scolastici. La maggior parte dei programmatori tende ad errare troppo nella direzione opposta.

    
risposta data 13.01.2015 - 06:47
fonte
104

Solo se la duplicazione è intenzionale anziché accidentale .

Oppure, metti un altro modo:

Solo se vorresti aspettarti per co-evolversi in futuro.

Ecco perché:

A volte, due pezzi di codice succedono per diventare uguali anche se non hanno nulla a che fare l'uno con l'altro. In questo caso, deve resistere all'impulso di combinarli, perché la prossima volta che qualcuno esegue la manutenzione su uno di essi, quella persona non si aspetta le modifiche da propagare a un chiamante inesistente e tale funzione potrebbe interrompersi di conseguenza. Quindi devi solo calcolare il codice quando ha senso, non ogni volta che sembra ridurre le dimensioni del codice.

Regola generale:

Se il codice restituisce solo nuovi dati e non modifica i dati esistenti o ha altri effetti collaterali, è molto probabile che sia sicuro considerarlo come una funzione separata. (Non riesco a immaginare uno scenario in cui ciò possa causare una rottura senza cambiare completamente la semantica della funzione, a quel punto anche il nome della funzione o la firma dovrebbero cambiare, e in ogni caso dovresti stare attento in quel caso. )

    
risposta data 14.01.2015 - 09:38
fonte
60

No, non è sempre una buona pratica.

A parità di condizioni, lineare, il codice line-by-line è più facile da leggere che saltare intorno alle chiamate di funzione. Una chiamata di funzione non banale prende sempre dei parametri, quindi è necessario ordinare tutto ciò e fare salti contestuali mentali dalla chiamata di funzione alla chiamata di funzione. Favorisci sempre una migliore chiarezza del codice, a meno che tu non abbia una buona ragione per essere oscuro (ad esempio ottenere i necessari miglioramenti delle prestazioni).

Quindi perché il codice viene quindi refactored in metodi separati? Per migliorare la modularità. Per raccogliere funzionalità significative dietro un singolo metodo e dargli un nome significativo. Se non lo stai facendo, non hai bisogno di questi metodi separati.

    
risposta data 13.01.2015 - 05:41
fonte
25

Nel tuo particolare esempio, la creazione di una funzione può sembrare eccessiva; invece vorrei porre la domanda: è possibile che questo particolare saluto cambi in futuro? Come mai?

Le funzioni non vengono semplicemente utilizzate per concludere la funzionalità e facilitare il riutilizzo, ma anche per semplificare le modifiche. Se i requisiti cambiano, il codice incollato alla copia dovrà essere ricercato e modificato manualmente, mentre con una funzione il codice deve essere modificato solo una volta.

Il tuo esempio trarrebbe vantaggio da questo non tramite una funzione - poiché la logica è quasi inesistente - ma probabilmente una costante di GREET_OPENING . Questa costante potrebbe quindi essere caricata dal file in modo che il programma possa essere facilmente adattabile a lingue diverse, ad esempio. Si noti che questa è una soluzione approssimativa, un programma più complesso avrebbe probabilmente bisogno di un modo più raffinato per tracciare i18n, ma di nuovo dipende dai requisiti e dal lavoro da fare.

Alla fine si tratta di possibili requisiti e pianifica in anticipo le cose per facilitare il lavoro del tuo futuro.

    
risposta data 13.01.2015 - 11:31
fonte
22

Personalmente ho adottato la regola del tre - che giustifico chiamando YAGNI . Se devo fare qualcosa una volta che scriverò quel codice, due volte potrei semplicemente copiare / incollare (sì, ho appena ammesso di copiare / incollare!) Perché non avrò bisogno di nuovo, ma se ho bisogno di fare lo stesso cosa ancora una volta poi rifatterò ed estrarrò quel pezzo nel suo stesso metodo, ho dimostrato, a me stesso, che ci ne avrà di nuovo bisogno.

Sono d'accordo con ciò che hanno detto Karl Bielefeldt e Robert Harvey e la mia interpretazione di ciò che stanno dicendo è che la regola prevalente è la leggibilità. Se rende il mio codice più facile da leggere, allora considera di creare una funzione, tieni a mente cose come DRY e SLAP . Se riesco a evitare di cambiare livello di astrazione nella mia funzione, trovo che sia più facile da gestire nella mia testa, quindi non saltare tra le funzioni (se non riesco a capire quale funzione fa semplicemente leggendo il suo nome) significa meno interruttori nel mio processi mentali.
Allo stesso modo, non dovendo cambiare contesto tra funzioni e codice inline come print "Hi, Tom" funziona per me, in questo caso I potrebbe estrarre una funzione PrintNames() iff il resto della mia la funzione generale erano principalmente chiamate di funzione.

    
risposta data 13.01.2015 - 11:24
fonte
13

È raramente chiaro, quindi è necessario pesare le opzioni:

  • Scadenza (correggere la masterizzazione del server al più presto)
  • Leggibilità del codice (può influire sulla scelta in entrambi i casi)
  • Livello di astrazione della logica condivisa (correlato a sopra)
  • Requisito per il riutilizzo (vale a dire che ha esattamente la stessa logica importante o è semplicemente conveniente in questo momento)
  • Difficoltà di condivisione (qui è dove python brilla, vedi sotto)

In C ++, di solito vado secondo la regola del tre (cioè la terza volta ho bisogno della stessa cosa, la refactoring in un pezzo correttamente condivisibile), ma con l'esperienza è più facile fare quella scelta inizialmente come sai di più l'ambito, il software e dominio con cui stai lavorando.

Tuttavia, in Python è piuttosto leggero riutilizzare, piuttosto che ripetere, la logica. Più che in molte altre lingue (almeno storicamente), IMO.

Quindi, considera di riutilizzare la logica localmente, ad esempio creando un elenco dagli argomenti locali:

def foo():
    for name_list in (vip_list, guest_list): # can be list of tuples, for many args
        for name in name_list:
            print name

Puoi usare una tupla di tuple e dividerla direttamente nel ciclo for, se hai bisogno di diversi argomenti:

def foo2():
    for header, name_list in (('vips': vip_list), ('people': guest_list)): 
        print header + ": "
        for name in name_list:
            print name

o crea una funzione locale (forse il tuo secondo esempio è quello), il che rende la riutilizzazione logica esplicita ma mostra anche chiaramente che print_name () non è usato al di fuori della funzione:

def foo():
    def print_name(name_list):
        for name in name_list:
            print name

    print_name(vip_list)
    print_name(guest_list)

Le funzioni sono preferibili soprattutto quando è necessario interrompere la logica nel mezzo (cioè utilizzare return), in quanto l'interruzione o le eccezioni potrebbero ingombrare le cose inutilmente.

O è superiore alla ripetizione della stessa logica, IMO e anche meno ingombrante di una funzione globale / di classe che viene utilizzata solo da un chiamante (anche se due volte).

    
risposta data 13.01.2015 - 07:16
fonte
9

Tutte le best practice hanno una ragione particolare a cui puoi fare riferimento per rispondere a una domanda del genere. Dovresti sempre evitare le increspature, quando un potenziale cambiamento futuro implica anche cambiamenti ad altri componenti.

Quindi nel tuo esempio: Se ritieni di avere un saluto standard e vuoi assicurarti che sia lo stesso per tutte le persone, scrivi

def std_greeting(name):
    print "Hi, " + name

for name in ["Tom", "Mary"]:
    std_greeting(name)   # even the function call should be written only once

Altrimenti, dovresti prestare attenzione e cambiare il saluto standard in due punti, se dovesse cambiare.

Se, tuttavia, il "Ciao" è lo stesso solo per sbaglio e cambiare uno dei saluti non comporta necessariamente cambiamenti per l'altro, quindi tenerli separati. Pertanto, tienili separati se ci sono ragioni logiche per credere che il seguente cambiamento è più probabile:

print "Hi, Tom"
print "Hello, Mary"

Per la tua seconda parte, decidere quanto "impacchettare" nelle funzioni dipende probabilmente da due fattori:

  • mantieni i blocchi piccoli per la leggibilità
  • mantieni i blocchi abbastanza grandi in modo che le modifiche avvengano solo in pochi blocchi. Non è necessario raggruppare troppo perché è difficile tenere traccia del modello di chiamata.

Idealmente, quando si verifica un cambiamento penserai "Devo cambiare la maggior parte del seguente blocco" e non "Devo cambiare il codice da qualche parte all'interno di un grande blocco".

    
risposta data 13.01.2015 - 14:53
fonte
5

L'aspetto più importante delle costanti e delle funzioni nominate non è tanto il fatto che riducono la quantità di digitazione, ma piuttosto che "collegano" i diversi luoghi in cui vengono utilizzati. Per quanto riguarda il tuo esempio, considera quattro scenari:

  1. È necessario modificare entrambi i messaggi di saluto nello stesso modo, [ad es. a Bonjour, Tom e Bonjour, Mary ].

  2. È necessario modificare un saluto ma lasciare l'altro così com'è [ad es. Hi, Tom e Guten Tag, Mary ].

  3. È necessario modificare entrambi i messaggi di saluto in modo diverso [ad es. Hello, Tom e Howdy, Mary ].

  4. Nessun saluto deve mai essere cambiato.

Se non è mai necessario modificare entrambi i messaggi di saluto, non importa quale sia l'approccio adottato. L'uso di una funzione condivisa avrà l'effetto naturale che la modifica di qualsiasi saluto li cambi tutti allo stesso modo. Se tutti i saluti dovessero cambiare nello stesso modo, sarebbe una buona cosa. Se non dovessero, comunque, il saluto di ciascuna persona dovrà essere codificato o specificato separatamente; qualsiasi lavoro svolto facendoli utilizzare una funzione o specifiche comuni dovrà essere annullato (e sarebbe stato meglio non farlo in primo luogo).

Per essere sicuri, non è sempre possibile prevedere il futuro, ma se si ha motivo di ritenere che sia più probabile che entrambi i saluti debbano cambiare insieme, questo sarebbe un fattore a favore dell'uso del codice comune (o di un nominato costante); se si ha motivo di ritenere che sia più probabile che uno o entrambi debbano cambiare in modo che differiscano, sarebbe un fattore contro il tentativo di usare il codice comune.

    
risposta data 13.01.2015 - 18:58
fonte
4

Nessuno dei casi che offri sembra degno di refactoring.

In entrambi i casi, si sta eseguendo un'operazione che è espressa in modo chiaro e sintetico, e non c'è pericolo che venga apportata una modifica incoerente.

Ti consiglio di cercare sempre modi per isolare il codice dove:

  1. Esiste un'attività identificabile e significativa che puoi separare, e

  2. O

    a. l'attività è complessa da esprimere (tenendo conto delle funzioni disponibili) o

    b. l'attività viene eseguita più di una volta e hai bisogno di un modo per assicurarti che venga cambiata nello stesso modo in entrambi i luoghi,

Se la condizione 1 non è soddisfatta, non troverai l'interfaccia giusta per il codice: se provi a forzarla, finirai con un sacco di parametri, più cose che vuoi restituire, molta logica contestuale, e molto probabilmente non riesco a trovare un buon nome. Prova a documentare l'interfaccia che stai pensando in primo luogo, è un buon modo di testare l'ipotesi che sia il giusto raggruppamento di funzionalità e viene fornito con il bonus aggiuntivo che quando scrivi il tuo codice, è già specificato e documentato!

2a è possibile senza 2b: a volte ho preso il codice fuori dal flusso anche quando so che viene usato solo una volta, semplicemente perché spostarlo altrove e sostituirlo con una singola riga significa che il contesto in cui viene chiamato è improvvisamente molto più leggibile (specialmente se si tratta di un concetto facile che la lingua sembra difficile da implementare). È anche chiaro quando si legge la funzione estratta in cui la logica inizia e finisce e ciò che fa.

2b è possibile senza 2a: il trucco sta nel sentire quale tipo di cambiamenti sono più probabili. È più probabile che la politica aziendale cambi da "Ciao" ovunque a "Ciao" tutto il tempo o che il tuo messaggio di saluto cambi in un tono più formale se stai inviando una richiesta di pagamento o delle scuse per un'interruzione del servizio? A volte potrebbe succedere perché stai utilizzando una libreria esterna di cui non sei sicuro e vuoi essere in grado di sostituirla rapidamente con un'altra: l'implementazione potrebbe cambiare anche se la funzionalità non lo è.

Molto spesso, però, avrai una miscela di 2a e 2b. E dovrai usare il tuo giudizio, tenendo in considerazione il valore commerciale del codice, la frequenza con cui viene utilizzato, se è ben documentato e compreso, lo stato della tua suite di test, ecc.

Se noti lo stesso bit di logica usato più di una volta, devi assolutamente cogliere l'occasione per prendere in considerazione il refactoring. Se stai iniziando nuove asserzioni con più di n livelli di indentazione in più lingue, questo è un altro trigger un po 'meno significativo (scegli un valore di n con cui ti trovi comodo per la tua lingua: Python potrebbe essere 6, per esempio).

Finché pensi a queste cose e abbatti i grandi mostri spaghetti-code, dovresti essere a posto - non spendere così tanto tempo a pensare a quanto sia raffinato il tuo refactoring che tu non abbia " Ho tempo per cose come test o documentazione elaborati. Se ha bisogno di farlo, il tempo lo dirà.

    
risposta data 13.01.2015 - 23:08
fonte
4

Penso che dovresti avere un motivo per creare una procedura. Ci sono una serie di ragioni per creare una procedura. Quelli che ritengo più importanti sono:

  1. astrazione
  2. modularità
  3. navigazione codice
  4. aggiorna la coerenza
  5. ricorsione
  6. test

Astrazione

Una procedura può essere utilizzata per astrarre un algoritmo generale dai dettagli di particolari passaggi nell'algoritmo. Se riesco a trovare un'astrazione opportunamente coerente, questo mi aiuta a strutturare il modo in cui penso a ciò che fa l'algoritmo. Ad esempio, posso progettare un algoritmo che funzioni sugli elenchi senza dover necessariamente considerare la rappresentazione della lista.

Modularità

Le procedure possono essere utilizzate per organizzare il codice in moduli. I moduli possono spesso essere trattati separatamente. Ad esempio, costruito e testato separatamente.

Il modulo ben progettato in genere acquisisce un'unità coerente coerente di funzionalità. Pertanto possono essere spesso di proprietà di squadre diverse, sostituiti completamente con un'alternativa o riutilizzati in un contesto diverso.

Navigazione codice

Nei sistemi di grandi dimensioni, trovare il codice associato a un particolare comportamento del sistema può essere difficile. L'organizzazione gerarchica del codice all'interno di librerie, moduli e procedure può aiutare con questa sfida. In particolare se si tenta di a) organizzare le funzionalità con nomi significativi e prevedibili b) posizionare le procedure relative a funzionalità simili l'una accanto all'altra.

Coerenza aggiornamento

Nei sistemi di grandi dimensioni può essere difficile trovare tutto il codice che deve essere modificato per ottenere un particolare cambiamento nel comportamento. Utilizzare le procedure per organizzare la funzionalità del programma può renderlo più semplice. In particolare, se ogni bit della funzionalità del programma viene visualizzato solo una volta e in un gruppo di procedure coesive, è meno probabile (nella mia esperienza) che manchi da qualche parte l'aggiornamento o l'aggiornamento incoerente.

Si noti che è necessario organizzare le procedure in base al functionaility e alle astrazioni nel programma. Non basato sul fatto che due bit di codice siano uguali al momento.

ricorsione

L'uso della ricorsione richiede la creazione di procedure

Test

Di solito è possibile testare le procedure indipendentemente l'una dall'altra. Testare diverse parti del corpo di una procedura in modo indipendente è più difficile, poiché in genere è necessario eseguire la prima parte della procedura prima della seconda parte. Questa osservazione si applica spesso anche ad altri approcci per specificare / verificare il comportamento dei programmi.

Conclusione

Molti di questi punti riguardano la comprensibilità del programma. Potresti dire che le procedure sono un modo per creare una nuova lingua, specifica per il tuo dominio, con cui organizzare, scrivere e leggere, sui problemi e i processi nel tuo dominio.

    
risposta data 15.01.2015 - 16:10
fonte
3

In generale sono d'accordo con Robert Harvey, ma volevo aggiungere un caso per suddividere una funzionalità in funzioni. Per migliorare la leggibilità. Considera un caso:

def doIt(smth,smthElse)
    for x in getDataFromSomething(smth,smthElse):
        if not check(x,smth):
            continue
        process(x,smthElse)
        store(x) 

Anche se queste chiamate di funzione non vengono utilizzate da nessun'altra parte, c'è un notevole vantaggio nella leggibilità se tutte e 3 le funzioni sono considerevolmente lunghe e hanno cicli annidati ecc.

    
risposta data 13.01.2015 - 09:12
fonte
2

Non esiste una regola dura e veloce da applicare, dipenderà dalla funzione effettiva che verrebbe utilizzata. Per la stampa di un nome semplice non vorrei usare una funzione, ma se si tratta di una somma matematica sarebbe una storia diversa. Quindi creerai una funzione anche se viene chiamata solo due volte, questo per garantire che la somma matematica sia sempre la stessa se mai cambiata. In un altro esempio, se si sta facendo qualsiasi forma di convalida si utilizzerà una funzione, quindi nell'esempio se è necessario verificare che il nome sia più lungo di 5 caratteri si utilizzerà una funzione per garantire che vengano sempre eseguite le stesse convalide.

Quindi penso che tu abbia risposto alla tua stessa domanda quando hai affermato "Per i codici che richiedono più di due righe, dovrò scrivere una funzione". In generale dovresti utilizzare una funzione, ma devi anche usare la tua logica per determinare se c'è un qualsiasi tipo di valore aggiunto dall'uso di una funzione.

    
risposta data 13.01.2015 - 05:52
fonte
2

Sono arrivato a credere in qualcosa di refactoring che non ho visto menzionato qui, so che ci sono già molte risposte qui, ma penso che questo sia nuovo.

Sono stato uno spietato refactorer e un strong sostenitore di DRY da prima della nascita dei termini. Principalmente è perché ho difficoltà a mantenere una grande base di codice nella mia testa e in parte perché mi piace codificare DRY e non mi piace nulla della codifica C & P, in effetti è doloroso e terribilmente lento per me.

Il fatto è che insistere su DRY mi ha dato molta pratica in alcune tecniche che raramente vedo usare dagli altri. Un sacco di persone insistono sul fatto che Java sia difficile o impossibile da rendere DRY, ma in realtà non ci provano.

Un esempio di molto tempo fa è in qualche modo simile al tuo esempio. Le persone tendono a pensare che la creazione di GUI java sia difficile. Ovviamente lo è se si codifica in questo modo:

Menu m=new Menu("File");
MenuItem save=new MenuItem("Save")
save.addAction(saveAction); // I forget the syntax, but you get the idea
m.add(save);
MenuItem load=new MenuItem("Load")
load.addAction(loadAction)

Chiunque pensi che sia semplicemente folle ha assolutamente ragione, ma non è colpa di Java - il codice non dovrebbe mai essere scritto in questo modo. Queste chiamate al metodo sono funzioni destinate a essere racchiuse in altri sistemi. Se non riesci a trovare un tale sistema, costruiscilo!

Ovviamente non puoi codificare così, quindi devi fare un passo indietro e guardare il problema, che cosa sta facendo effettivamente quel codice ripetuto? Sta specificando alcune stringhe e il loro rapporto (un albero) e unendo le foglie di quell'albero alle azioni. Quindi quello che vuoi veramente è dire:

class Menu {
    @MenuItem("File|Load")
    public void fileLoad(){...}
    @MenuItem("File|Save")
    public void fileSave(){...}
    @MenuItem("Edit|Copy")
    public void editCopy(){...}...

Una volta che hai definito la tua relazione in un modo che è succinta e descrittiva, allora scrivi un metodo per affrontarla - in questo caso fai scorrere i metodi della classe passata e costruisci un albero poi usalo per costruisci i tuoi menu e azioni e (ovviamente) visualizza un menu. Non avrai duplicazioni e il tuo metodo è riutilizzabile ... e probabilmente più facile da scrivere rispetto a un gran numero di menu sarebbe stato, e se ti piace davvero programmare, hai avuto MOLTO più divertimento. Questo non è difficile: il metodo che devi scrivere è probabilmente meno linee rispetto a creare il tuo menu a mano sarebbe!

Il fatto è che, per fare questo bene, devi praticare molto. È necessario essere bravi ad analizzare esattamente quali informazioni uniche si trovano nelle parti ripetute, estrarre tali informazioni e capire come esprimerle bene. Imparare a usare strumenti come l'analisi delle stringhe e le annotazioni aiuta molto. Imparare ad essere molto chiari sulla segnalazione degli errori e sulla documentazione è molto importante.

Prendi la pratica "libera" semplicemente codificando bene - è molto probabile che una volta che ci sarai riuscito a capire che la codifica di qualcosa ASCIUTTO (incluso scrivere uno strumento riutilizzabile) è più veloce della copia e dell'incollatura e di tutti gli errori , errori duplicati e modifiche difficili che il tipo di codifica causa.

Non penso che sarei in grado di godermi il mio lavoro se non avessi esercitato le tecniche di DRY e costruito gli strumenti il più possibile. Se dovessi prendere un taglio in pagamento per non dover fare programmi di copia e incolla, lo prenderei.

Quindi i miei punti sono:

  • Copia e amp; Incolla costa più tempo a meno che tu non sappia come rifattorizzare bene.
  • Impari bene a fare il refactoring - insistendo su DRY anche nei casi più difficili e banali.
  • Sei un programmatore, se hai bisogno di un piccolo strumento per rendere il tuo codice ASCIUTTO, costruiscilo.
risposta data 15.01.2015 - 05:41
fonte
1

In generale, è una buona idea dividere qualcosa in una funzione che migliori la leggibilità del tuo codice, oppure, se la parte che viene ripetuta spesso è in qualche modo fondamentale per il sistema. Nell'esempio sopra, se avessi bisogno di salutare i tuoi utenti a seconda delle impostazioni locali, sarebbe logico avere una funzione di benvenuto separata.

    
risposta data 04.03.2015 - 14:26
fonte
1

Come corollario del commento di @ DocBrown a @RobertHarvey sull'uso delle funzioni per creare astrazioni: se non riesci a trovare un nome di funzione adeguatamente informativo che non sia significativamente più conciso o più chiaro del codice sottostante, sei non astrarre molto. In assenza di altri buoni motivi per renderlo una funzione, non è necessario farlo.

Inoltre, un nome di funzione raramente cattura la sua semantica completa, quindi potrebbe essere necessario controllare la sua definizione, se non è abbastanza comune da essere familiare. In particolare, oltre a un linguaggio funzionale, potrebbe essere necessario sapere se ha effetti collaterali, quali errori possono verificarsi e come vengono gestiti, la sua complessità temporale, se alloca e / o libera risorse e se è thread- cassetta di sicurezza.

Naturalmente, per definizione, stiamo considerando solo le funzioni semplici, ma ciò vale in entrambi i casi: in tali casi, l'integrazione non è probabile che aggiunga complessità. Inoltre, il lettore probabilmente non si renderà conto che è una funzione semplice finché non appare. Anche con un IDE che ti collega alla definizione, il salto visivo è un ostacolo alla comprensione.

In generale, il codice ricorsivo del factoring in più funzioni più piccole ti porterà infine al punto in cui le funzioni non hanno più un significato indipendente, perché quando i frammenti di codice da cui sono fatti diventano più piccoli, quei frammenti ottengono più del loro significato da il contesto creato dal codice circostante. Come un'analogia, pensala come un'immagine: se fai lo zoom troppo vicino, non riesci a distinguere ciò che stai guardando.

    
risposta data 14.01.2015 - 17:53
fonte

Leggi altre domande sui tag