Ha mai senso che un refattore finisca con un LOC più alto? [chiuso]

25

Ci sono casi in cui un codice più dettagliato (come in più istruzioni logiche) è più pulito di un codice più conciso?

    
posta wrongusername 12.10.2018 - 07:24
fonte

4 risposte

71

Per rispondere, prendiamo un esempio del mondo reale che mi è successo. In C # una libreria che mantengo, ho avuto il seguente codice:

TResult IConsFuncMatcher<T, TResult>.Result() =>
    TryCons(_enumerator) is var simpleMatchData && !simpleMatchData.head.HasValue
        ? _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
        : _recursiveConsTests.Any() 
            ? CalculateRecursiveResult() 
            : CalculateSimpleResult(simpleMatchData);

Discutendo di questo con i colleghi, il verdetto unanime è stato che le espressioni ternarie nidificate, abbinate all'utilizzo "intelligente" di is var , hanno prodotto un codice terso, ma di difficile lettura.

Quindi l'ho refactored per:

TResult IConsFuncMatcher<T, TResult>.Result()
{
    var simpleMatchData = TryCons(_enumerator);

    if (!simpleMatchData.head.HasValue)
    {
        return _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
    }

    return _recursiveConsTests.Any() 
        ? CalculateRecursiveResult() 
        : CalculateSimpleResult(simpleMatchData);
}

La versione originale conteneva solo un'espressione composta con una percentuale implicita di% co_de. La nuova versione ora contiene una dichiarazione di variabile esplicita, un'istruzione return e due espliciti if . Contiene più istruzioni e più righe di codice. Eppure tutti quelli che ho consultato consideravano più facile leggere e ragionare, che sono aspetti chiave del "codice pulito".

Quindi la risposta alla tua domanda è un "sì" enfatico, più verboso può essere più pulito del codice conciso ed è quindi un valido refactoring.

    
risposta data 12.10.2018 - 08:52
fonte
29

1. Mancanza di correlazione tra LOC e qualità del codice.

L'obiettivo del refactoring è migliorare la qualità di un pezzo di codice.

LOC è una metrica molto basilare che, a volte, si correla con la qualità di un pezzo di codice: ad esempio, un metodo con poche migliaia di LOC è probabile che abbia problemi di qualità. Va notato, tuttavia, che LOC non è la metrica solo e in molti casi manca la correlazione con la qualità. Ad esempio, un metodo 4 LOC non è necessariamente più leggibile o più gestibile rispetto a un metodo 6 LOC.

2. Alcune tecniche di refactoring consistono nell'aggiungere LOC.

Se prendi un elenco di tecniche di refactoring , puoi facilmente individuare quelle che consistono in aggiungere LOC. Esempi:

Entrambe sono tecniche di refactoring molto utili e il loro effetto sulla LOC è del tutto irrilevante quando si valuta se usarle o meno.

Evita di usare LOC.

LOC è una metrica pericolosa. È molto facile da misurare ed è molto difficile da interpretare correttamente.

Finché non si acquisisce familiarità con le tecniche di misurazione della qualità del codice, considerare di evitare di misurare LOC in primo luogo. La maggior parte delle volte, non otterrai nulla di rilevante, e ci sarebbero casi in cui ti indurre in errore a ridurre la qualità del tuo codice.

    
risposta data 12.10.2018 - 09:10
fonte
12

Se vuoi vedere il risultato finale di ridurre al minimo il conteggio dei byte o il conteggio LoC del tuo codice sorgente, dai un'occhiata alla sezione Impila il sito Golf per il codice di scambio .

Se il tuo codice sorgente è ridotto in questo modo, presto avrai un disordine irraggiungibile. Anche se sei la persona che ha scritto questo codice e lo capisci pienamente al momento, quanto sarai efficiente quando tornerai in esso tra sei mesi? Non vi è alcuna prova che un codice così minimale sia effettivamente più veloce.

Il codice dovrebbe essere scritto in modo tale che ogni membro del tuo team possa guardarlo e capire cosa sta facendo immediatamente.

    
risposta data 12.10.2018 - 11:14
fonte
1

Sì, il refactoring può sicuramente comportare più righe di codice.

Il caso IMO più comune è quando prendi il codice che non è generico e lo rendi più generico / flessibile . Generare codice facilita notevolmente le linee di codice (a volte di due o più fattori).

Se ti aspetti che il codice generico venga usato da altri (invece che come un componente software interno) come una libreria, di solito finisci con l'aggiungere codice unittest e markup di documentazione in codice che aumenterà nuovamente le righe di codice .

Ad esempio, ecco uno scenario molto comune che accade per ogni sviluppatore di software:

  • il tuo prodotto ha bisogno di una nuova funzione urgente ad alta priorità o di una correzione o di un miglioramento dei bug in due settimane (o qualunque time-frame è considerato urgente per la dimensione del tuo progetto / dimensione aziendale / ecc.)
  • lavori duro e offri XYZ in orario e funziona. Congratulazioni! Ottimo lavoro!
  • Mentre stavi sviluppando XYZ la tua progettazione / implementazione di codice esistente non supportava realmente XYZ ma eri in grado di spingere XYZ nella base di codice
  • il problema è che lo shim è brutto e ha un terribile odore di codice perché hai fatto delle cose complicate / intelligenti / brutte / cattive-pratiche-ma-kinda-works
  • quando trovi il tempo dopo ti rifatti il codice che può cambiare molte classi o aggiungere un nuovo livello di classi e la tua nuova soluzione è "fatta bene" e non ha più il cattivo odore di codice. .. comunque facendolo il "giusto modo" ora prende più linee di codice.

Alcuni esempi concreti che mi vengono fuori di testa:

  • per un'interfaccia a riga di comando potresti avere 5000 righe di codice if / else-if o potresti usare callback ... ogni callback sarebbe molto più piccolo e più facile da leggere / test / verificare / debug / ecc. ma se conti le linee di codice le brutte 5000 linee di codice if / else-if sarebbero probabilmente più piccole
  • per una parte di codice di elaborazione che supporta N metodi di elaborazione , potresti usare nuovamente le istruzioni if / else che apparirebbero le più brutte ...
    • o potresti passare a callback che sarebbero più belli / migliori, ma i callback richiedono più righe di codice (comunque esegui comunque la compilazione)
    • oppure potresti astrarre ulteriormente e fare plugin che possono essere modificati in fase di runtime. i plugin sono carini perché non devi ricompilare il prodotto principale per ogni nuovo plugin o modifica ad un plugin esistente. e puoi pubblicare l'API in modo che altri possano estendere il prodotto. MA ancora una volta un approccio plugin usa più linee di codice.
  • per una GUI crei un nuovo grande widget
    • tu o un collega si nota che il nuovo widget sarebbe ottimo per XYZ e ABC ma in questo momento il widget è strettamente integrato solo per funzionare con XYZ
    • si rifatta il widget affinché funzioni per entrambi, ma ora le linee totali del codice aumentano
risposta data 12.10.2018 - 14:27
fonte

Leggi altre domande sui tag