Il mio codice dovrebbe essere ASCIUTTO o leggibile se non può essere entrambi?

14

Sto scrivendo il codice Ruby per un semplice esercizio di crittografia e ho frequentemente imbattuto in questo dilemma (l'esercizio è un cifrario solitario se devi saperlo). Si tratta di capire se dovrei estrapolare la mia logica con variabili descrittive e istruzioni a step singolo che rendano la funzione leggibile anziché una dichiarazione concisa, anche densa che elimini la ripetizione e / o riduca al minimo le opportunità di errori.

Il mio esempio più recente: il mio programma prende input e, a causa delle rigide linee guida del formato, può facilmente determinare se l'input debba essere crittografato o decrittografato. Per semplificare, una volta che la chiave di crittografia e il messaggio sono stati convertiti / generati per essere compatibili, si tratta di sottrarre la chiave dal messaggio crittografato o di aggiungere la chiave a un messaggio non crittografato, per ottenere l'output desiderato (si pensi alla chiave come crittografia, messaggio + crittografia = codice; codice - crittografia = messaggio). La posizione DRY mi dice che dovrei convertire il mio messaggio crittografato in modo diverso dal mio messaggio non crittografato in modo che la funzione che prende la chiave di crittografia e la applichi al messaggio non debba mai distinguere. Ho scoperto che questo significa che ho bisogno di alcune istruzioni nidificate nella funzione, ma la logica sembra essere solida. Questo codice, tuttavia, non è facilmente leggibile. Ciò richiederebbe alcuni commenti per essere chiari.

Potrei, d'altra parte, scrivere due diverse funzioni chiamate in base a un flag che viene impostato quando l'applicazione determina la crittografia o la decrittografia. Ciò sarebbe più semplice da leggere, ma duplicherebbe la funzione di alto livello dell'applicazione della chiave di crittografia a un messaggio (causandone la crittografia o la decrittografia).

Dovrei inclinarmi verso un codice leggibile o un codice conciso? O ho perso un altro modo per ottenere questa funzionalità e soddisfare entrambi i principi? Si tratta di una posizione su una scala in cui è necessario considerare lo scopo del progetto e prendere le decisioni migliori per raggiungere questo scopo?

Finora, tendo a enfatizzare il codice conciso e DRY su un codice leggibile.

    
posta lutze 10.04.2013 - 03:47
fonte

7 risposte

19

DRY è una linea guida, non una religione. Coloro che la prendono al punto di ASCIUTARSI sopra ogni altra cosa, l'hanno presa troppo lontano.

Innanzitutto, il codice utilizzabile è fondamentale. Se il codice non è utile e utilizzabile, non lo è ... e non c'è alcun motivo per scriverlo in primo luogo.

In secondo luogo, un giorno qualcuno dovrà mantenere il proprio codice. Se il tuo codice non è gestibile, romperà il tuo design "bello" denso, conciso, ASCIUTTO mentre maledice il tuo nome. Non farlo. Sono stato quella persona e ogni volta che vedo un certo nome nell'annotazione del codice, rabbrividisco.

Creare codice denso privo di "variabili descrittive" e attaccare tutto in espressioni ternarie nidificate con lambda senza alcuna documentazione è intelligente. È bello sapere che puoi farlo, ma non farlo. Il codice intelligente è molto difficile da eseguire il debug. Evita di scrivere codice intelligente .

La maggior parte del tempo speso nel software viene spesa per la manutenzione del software, non per la prima volta. Scrivi il codice in modo che tu (o qualcun altro) possa risolvere rapidamente e facilmente bug e aggiungere funzionalità come richiesto con il minor numero di modifiche alla progettazione ideali.

    
risposta data 10.04.2013 - 04:25
fonte
17

Non sono sicuro in base alla domanda che hai capito ASCIUTO. Il codice DRY non è lo stesso di quello conciso. Molto spesso è il contrario.

Qui, non sono sicuro di quale sia il grosso problema per questo esempio. Crea una funzione per crittografare, una funzione per decrittografare, helpers per funzionalità comuni (mix byte), e un semplice front end per prendere input e determinare criptare / decifrare ... Non ripetere te stesso.

In generale, tuttavia, esistono sia DRY che la leggibilità per aiutare a mantenere ed estendere il codice. Non tutti gli scenari sono uguali, un grande successo di leggibilità per rimuovere una piccola ripetizione non è buono, e nessuno dei due è duplicazione per aggiungere un po 'di leggibilità.

Se premuto, preferirei la leggibilità. Il codice duplicato può ancora essere testato: il codice illeggibile ti porta a fare (e a testare) la cosa sbagliata.

    
risposta data 10.04.2013 - 04:24
fonte
12

Non ho familiarità con il tuo caso specifico, ma posso dare alcune linee guida generali.

Lo scopo sia di leggibilità che di ESSERE è manutenibilità .

La manutenibilità è importante nella maggior parte delle situazioni, passerai più tempo a mantenere il codice che a scriverlo. Questo è particolarmente vero se consideri che scrivere codice sia un tipo speciale di manutenzione.

Sfortunatamente, ASCIUTTO è spesso frainteso. Questo è in parte perché sembra così semplice, ma come un sacco di cose semplici può essere, beh ... complicato.

L'intenzione di DRY è che ogni unità di funzionalità esiste in un solo posto. Se il principio viene seguito, il responsabile del codice che ha il compito di modificare o verificare che la funzionalità possa gestire il codice in una sola volta. Se DRY non viene seguito, sussiste il pericolo reale che alcune copie della funzionalità non vengano mantenute correttamente.

La violazione più evidente di DRY è la codifica copia-incolla, in cui interi blocchi di codice sono ripetuti verbatum nella base del codice. Questo è sorprendentemente comune nella mia esperienza e in nessun modo questo aggiunge alla leggibilità. Pertanto, il refactoring del codice per introdurre un metodo comune aumenta invariabilmente la conformità e la leggibilità di DRY.

La seconda violazione più evidente è "copia-incolla e cambia un po '". Anche in questo caso, il refactory per introdurre un metodo di comon con parametri, o interrompere una funzione in fasi e sottrarre gli elementi comuni, aumenta quasi sempre la leggibilità.

Poi ci sono le violazioni più sottili, in cui la funzionalità è duplicata ma il codice è diverso. Questo non è sempre facile da individuare, ma quando lo vedi e il refactoring tira il codice comune in un singolo metodo / classe / funzione, il codice è usualmente più leggibile di quanto fosse prima.

Infine, ci sono i casi di ripetizione del design. Ad esempio, potresti aver usato lo schema di stato più volte nella tua base di codice e stai considerando il refactoring per eliminare questa ripetizione. In questo caso, procedere con cautela. Potresti ridurre la leggibilità introducendo più livelli di astrazione. Allo stesso tempo, non si tratta veramente di duplicare la funzionalità, ma di duplicare l'astrazione. A volte ne vale la pena ... ma spesso non lo è. Il tuo principio guida sarà chiedere "quale di questi è più gestibile"

Ogni volta che faccio queste chiamate di giudizio cerco di considerare la quantità di tempo che le persone impiegheranno per mantenere il codice. Se il codice è la funzionalità di core business, probabilmente avrà bisogno di più manutenzione. In questi casi, mi propongo di rendere il codice mantenibile per le persone che hanno familiarità con la base di codice e le astrazioni coinvolte. Sarei più felice di introdurre un po 'più di astrazione per ridurre la ripetizione. Al contrario, uno script che viene usato raramente e mantenuto di rado potrebbe essere meno facile da comprendere per i manutentori, se ciò comporta un'astrazione eccessiva. In tal caso, sbaglierei dalla parte della ripetizione.

Considero anche il livello di esperienza degli altri membri della mia squadra. Evito le astrazioni "fantasiose" con sviluppatori inesperti, ma sfrutto modelli di design riconosciuti dall'industria con gruppi più maturi.

In concomitanza, la risposta alla tua domanda è fare tutto ciò che rende il tuo codice più gestibile. Ciò che questo significa nel tuo scenario dipende da te decidere.

    
risposta data 10.04.2013 - 08:52
fonte
7

Se le tue funzioni diventano più complicate e più lunghe (quindi meno leggibili) quando provi a renderle ASCIUTTE, allora stai sbagliando. Stai cercando di mettere troppa funzionalità in una funzione perché pensi che questo sia l'unico modo per evitare di ripetere gli stessi pezzi di codice in una seconda funzione.

Rendere il codice DRY significa quasi sempre refactoring di funzionalità comuni a funzioni più piccole. Ognuna di queste funzioni dovrebbe essere più semplice (e quindi più leggibile) di quella originale. Per mantenere tutto nella funzione originale allo stesso livello di astrazione, questo può anche significare rifattorizzare parti aggiuntive che non sono usate altrove. La tua funzione originale diventa quindi una "funzione di alto livello", chiama i più piccoli e diventa più piccola e più semplice.

Facendo questo, di conseguenza, si passa principalmente a diversi livelli di astrazione nel codice, e alcune persone credono che questo tipo di codice sia meno leggibile. Per la mia esperienza, questo è un errore. Il punto chiave qui è quello di dare alle funzioni più piccole nomi validi, introdurre tipi di dati e astrazioni ben definiti che possono essere facilmente afferrati da una seconda persona. In questo modo "DRY" e "readability" dovrebbero entrare in conflitto solo molto raramente.

    
risposta data 10.04.2013 - 08:53
fonte
2

Anche se non sono sicuro di cosa stia causando il problema, la mia esperienza è che quando trovi DRY e leggibilità in conflitto che dice che è il momento di rifattorizzare qualcosa.

    
risposta data 10.04.2013 - 05:33
fonte
0

Sceglierei leggibile (= mantenibile) anziché DRY in qualsiasi giorno della settimana. In realtà entrambi si allineano spesso, qualcuno che ottiene il concetto di DRY generalmente produce codice (soprattutto) leggibile.

    
risposta data 10.04.2013 - 04:23
fonte
0

Molto molto molto molto molto poche volte nella mia carriera ho trovato un caso legittimo che intacca la leggibilità contro il DRY. Rendilo leggibile prima. Dai un nome alle cose. Copia e incolla se necessario.

Ora fai un passo indietro e guarda la totalità che hai creato, come un artista che si allontana per guardare il loro dipinto. Ora puoi identificare correttamente la ripetizione.

Il codice ripetuto dovrebbe essere refactored nel suo proprio metodo o essere estratto nella relativa classe.

Il codice ripetuto dovrebbe essere l'ultima risorsa. Leggibile E ASCIUTTO prima, non leggibile se limiti l'ambito del codice ripetuto.

    
risposta data 10.03.2017 - 00:10
fonte

Leggi altre domande sui tag