Ripetizione del codice vs metodo multi-responsabile


11

Cerco di seguire il principio di responsabilità singola (SRP) e anche di omettere le ripetizioni del codice. Tuttavia ci sono spesso luoghi in cui ci sono ripetizioni di codice che non sono altro che blocchi di codice di invocazioni che sono resistenti all'estrazione in almeno un metodo chiamato significativo:

DoAction1();
DoAction2();

if (value)
    DoAction3();

DoAction4();

Qual è il modo migliore per estrarre tale codice in un metodo e come nominarlo?


1
Perché sono resistenti all'estrazione in un diverso metodo significativo?
Chandranshu,

Tutte le azioni fanno qualcosa di indipendente. Avrei dovuto scrivere: void MethodThatDoAction1ThenAction2AndAction3IfValueAndThenAction4(). Avrei preferito vedere più significato in: CodeBlock1().
yBee

4
Quindi si tratta semplicemente di nominare correttamente il metodo estratto, giusto? Temo che non esista una soluzione universale e dovrai farlo caso per caso. Se stai ripetendo esattamente lo stesso codice in più di 1 posto, c'è sicuramente un significato per le tue azioni e devi cercare con attenzione (potrebbe essere in discussione) di trovare quel significato e dargli un nome.
Chandranshu,

1
Se è una consolazione, il vincitore della primavera per i nomi di classe lunga AbstractInterruptibleBatchPreparedStatementSetterè solo un po 'più piccolo del tuo metodo.
Chandranshu,

1
@Chandranshu Credo che i tuoi commenti funzionerebbero bene come risposta a questa domanda.
Simon Forsberg,

Risposte:


13

Penso che si tratti semplicemente di nominare correttamente il metodo estratto. Temo che non esista una soluzione universale e dovrai farlo caso per caso. Se stai ripetendo esattamente lo stesso codice in più di 1 posto, c'è sicuramente un significato per le tue azioni e devi cercare con attenzione (potrebbe essere in discussione) di trovare quel significato e dargli un nome.

Se è una consolazione, il vincitore della primavera per i nomi di classe lunga è AbstractInterruptibleBatchPreparedStatementSetterdi 49 caratteri.


11

In realtà stai soffrendo del compito più difficile da svolgere da parte di un programmatore - Naming Things . Scusami per una risposta così acerba, ma non ho resistito. Puoi scoprire che molte persone soffrono di questo , anche in Internet puoi trovare questo tipo di saggio .

Ora se il tuo codice ripetitivo è tutto insieme risultante un lavoro e quei metodi non vengono utilizzati da altri metodi, allora sono semplicemente il metodo Helpers e quindi il metodo risultante può essere nominato come doXXXo makeXXX... Penso che tu ottenga il punto.

Come ha detto Chandranshu "Se stai ripetendo questo [...] significato e dagli un nome." è al punto e appropriato.

inserisci qui la descrizione dell'immagine

Foto per gentile concessione: CodeChef Pagina Facebook Foto


2

Penso che stai spingendo troppo oltre il principio della ripetizione del codice. Pensa al punto di evitare la ripetizione del codice. Il punto è ridurre la quantità di codice che deve essere verificato quando si verifica un cambiamento nella logica e aumentare la comprensione prendendo in considerazione blocchi ovviamente intesi in modo simile.

Gli svantaggi del factoring al fine di evitare la ripetizione sono che se uno dei blocchi condivisi deve cambiare, ora è necessaria un'eredità ancora più complessa o un passaggio dall'implementazione standard a quella non standard.

Così attentamente soppesare la possibilità che la logica anche se uno di questi blocchi cambi senza che gli altri si confrontino con i benefici di comprensione ottenuti prendendo in considerazione questa comunanza. Se un'implementazione potrebbe dividersi dalle altre, è molto meglio semplicemente ripetere il codice.

Pur mantenendo questo codice ripetuto, man mano che diventa più complesso e il dominio del problema diventa più definito, potresti trovare più appropriato considerare le sezioni ripetute, ora più complesse, ma anche più definite.

Di solito cerco di mantenere la stessa editor di testo per un po 'finché non riesco a vedere se qualcosa che sembra essere ripetitivo risulta essere degno di essere preso in considerazione. Tengo solo la ripetizione, ma tengo d'occhio il futuro di quel blocco mantenendolo testualmente facile da abbinare in seguito.

Molte volte, la stessa uguaglianza e l'eventuale factoring iniziano a dissipare, come regole aziendali reali, capricciose e logiche altamente dipendenti, spesso arbitrarie; come la gestione delle stranezze di diverse implementazioni di database comuni (ANSI_NULLS o alcuni di questi vengono in mente) vengono aggiunti; forzare quella che sembrava una pura logica in un pasticcio contorto, cercando di fornire una logica decisionale ragionevole e difendibile di fronte al disordine dello stato del settore.

Mi sembra che se le persone provassero a capire cosa si sta cercando di considerare, avremmo un'intera libreria di costrutti inutili come Do1Then2If2False Do1IfTrueDo2.

Deve essere più complesso e più chiaro che il blocco non cambierà per giustificarlo.

È un software . Puoi tornare indietro e modificare un paio di blocchi che sono gli stessi in questo momento. Ci vorranno 5 minuti. E puoi risparmiare ore di factoring sprecato, e quindi ore in più di eredità sprecata e cambio di sviluppo, semplicemente lasciandolo e assicurandoti di avere una buona tastiera anti-RSI.


Mi piace la parte che estrae l'essenza della ripetizione del codice: per ridurre la quantità di codice che deve essere verificata quando c'è un cambiamento nella logica
yBee

1

Se stai veramente seguendo il principio di responsabilità singola, questo blocco di codice deve avere uno scopo specifico, giusto? Altrimenti questi metodi sarebbero in classi separate.

Quindi, qual è lo scopo di questo blocco di codice? Determinalo e dovresti riuscire a trovare un nome.

Se non riesci ancora a capire il nome di questa cosa, allora forse questi metodi in realtà non appartengono affatto. Vale a dire questo blocco di classe / codice ha più di una responsabilità. In tal caso, il refactoring per suddividere i compiti può rivelare un nome che rivela meglio lo scopo.


1

Ho avuto una situazione che potrebbe essere simile alla tua:

Esiste una classe che definisce la funzionalità dell'oggetto che rappresenta:

class Functionality
{
protected:
void functionA();
void functionB();
...
void functionZ();
}

Quindi c'è una classe che definisce i flussi di lavoro per operazioni di alto livello che l'oggetto esegue:

class Workflows: private Functionality
{
    void WorkflowA()
    {
        functionA();

        if (m_bValue) {
            functionB();
        }

        functionC();
    }
    ...
    void WorkflowB();
}

Se ti trovi in ​​una situazione simile, identifica cosa rappresentano le tue classi (in questo caso funzionalità / flussi di lavoro) e dai un nome ai metodi di conseguenza.

Dichiarazione di non responsabilità: i nomi delle classi utilizzati in questo esempio sono grossolanamente inaccurati, ma i nomi dei metodi forniscono un indizio. Discrezione consigliata.

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.