Devo sacrificare nomi di variabili più brevi per un codice "a colonna" più lungo?


17

Sono un programmatore amatoriale in una classe CS che cerca di imparare le abilità di programmazione adeguate. Ecco come appare il mio codice, i suoi bordi si estendono a 103 colonne.

int extractMessage(char keyWord[25], char cipherText[17424],
                   int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);


    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }

Prima che avessi quei nomi di variabili super lunghi avevo cose come me, j, k, ma il mio professore insiste sul fatto che non dovremo usare variabili del genere nel "mondo professionale" e che anche le variabili abbreviate come lenWord sono insufficienti perché le persone potrebbero presumere sta per "Lennard's World Literature". Dice di scegliere nomi di variabili significativi, ma così facendo mi sento come se avessi infranto la Regola d'oro del codice per tenerlo sotto 80 colonne. Come posso aggirare questo?


26
Continua così; aggiungi altri nomi utili. Si può pensare a un modo per descrivere cipherColumn + (rowSize*nextWord) + nextWordche rende chiaro ciò che il calcolo è per , per esempio? Scommetto che quel nome è più breve del calcolo, quindi ottieni un vantaggio di leggibilità e una lunghezza della linea ridotta. Inoltre, non allineare le assegnazioni o devi spostarle tutte se rinomini la variabile più lunga.
jonrsharpe,

2
Hmm .. quindi stai dicendo che dovrei creare una nuova variabile e memorizzare il risultato di cipherColumn + (rowSize * nextWord) + nextWord in esso in modo da poterlo usare ulteriormente? È quello che fanno i professionisti? Sto chiedendo sinceramente
RaulT

8
Sì, questo è il mio suggerimento. Sono un professionista ed è quello che farei, quindi ... almeno alcuni di loro.
jonrsharpe,

11
regola d'oro è scrivere codice che possa essere letto e compreso. scriviamo codice per altre persone (!) non per macchine. per le macchine esiste un codice macchina. per alcuni, il codice che assomigli a quello che hai descritto (nomi di singole lettere, ecc.) è una mancanza di rispetto per gli altri programmatori (e per il futuro, perché dimenticherai nelle prossime settimane o mesi). non c'è motivo di attenersi a 80 colonne, non è MS DOS negli anni '80.
rsm,

3
@stijn sì, ma è l'ultima volta che ne abbiamo avuto bisogno. proprio come non compilo il mio codice c per il processore 8086 a 8 bit nel caso in cui ho bisogno di memorizzarlo su schede perforate, non penso nemmeno che la colonna d'oro di 80 colonne abbia alcun significato nel 21 ° secolo. dovremmo estendere questa tecnologia, non sederci negli anni '80 e pensare che ci renda hacker intelligenti. intelligente è semplicità, leggibilità e spinge la tecnologia al massimo. abbiamo monitor full-hd, è tempo di usarlo.
rsm,

Risposte:


24

Normalmente quando vedo un codice pubblicato qui come il tuo, lo modifico, perché odiamo lo scorrimento orizzontale. Ma poiché fa parte della tua domanda, ti mostrerò la modifica qui:

int extractMessage(char keyWord[25], char cipherText[17424],
                   int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);


    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }
}

Quella pausa può essere sorprendente, ma è più leggibile rispetto alla versione con scorrimento orizzontale, ed è meglio che accorciando i nomi da i, je k.

Non è che non si dovrebbe mai usare i, je k. Questi sono nomi validi quando si indicizzano 3 forloop nidificati . Ma qui i nomi sono davvero il mio unico indizio su cosa ti aspettavi che accadesse. Soprattutto perché questo codice in realtà non fa nulla.

La migliore regola da seguire sulla lunghezza del nome della variabile è l'ambito. Più a lungo vive una variabile, più altre variabili con cui il suo nome deve competere. Il nome CandiedOrange è unico nello scambio di stack. Se fossimo in chat, potresti semplicemente chiamarmi "Candy". Ma in questo momento, sei in un ambito in cui quel nome potrebbe essere confuso con Candide , Candy Chiu o Candyfloss . Quindi più lungo è l'ambito, più lungo dovrebbe essere il nome. Più breve è l'ambito, più breve può essere il nome.

La lunghezza della linea non dovrebbe mai dettare la lunghezza del nome. Se ne hai voglia, trova un modo diverso di strutturare il tuo codice. Abbiamo molti strumenti per aiutarti a farlo.

Una delle prime cose che cerco è il rumore inutile per sbarazzarsi di. Purtroppo questo esempio non fa nulla, quindi è tutto rumore inutile. Ho bisogno di qualcosa con cui lavorare, quindi prima facciamolo fare qualcosa.

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    int lengthOfWord   = 0;
    int lengthOfCipher = 0;

    lengthOfWord = length(keyWord);
    lengthOfCipher = length(cipherText);

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
            continue;
        }
    }
    return cipherColumn;
}

Ecco, ora fa qualcosa.

Ora che fa qualcosa, posso vedere di cosa posso liberarmi. Questa roba non è nemmeno usata. continueNeanche questo fa nulla.

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn    = 0;
    int cipherColumn = 0;
    int offset       = 1;
    int nextWord     = 1;

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

Facciamo alcune piccole modifiche agli spazi bianchi, perché viviamo in un mondo di controllo del codice sorgente ed è bello quando l'unica ragione per cui una riga viene segnalata come cambiata è perché sta facendo qualcosa di diverso, non perché una parte di essa doveva essere allineata in una colonna.

int calcCipherColumn(char keyWord[25], char cipherText[17424],
                     int rowSize, char message[388]) 
{
    int keyColumn = 0;
    int cipherColumn = 0;
    int offset = 1;
    int nextWord = 1;

    while (keyWord[keyColumn] != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyWord[keyColumn + offset] 
        != cipherText[cipherColumn + (rowSize*nextWord) + nextWord]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

Sì, lo so che è leggermente meno leggibile, ma altrimenti farai impazzire le persone che usano gli strumenti vdiff per rilevare le modifiche.

Ora risolviamo queste sciocche interruzioni di linea che abbiamo perché stiamo cercando di rimanere sotto i limiti di lunghezza della linea.

int calcCipherColumn(
        char keyWord[25], 
        char cipherText[17424],
        int rowSize, 
        char message[388]
) {
    int keyColumn = 0;
    int keyOffset = 1;

    int nextWord = 1;
    int cipherColumn = 0;
    int cipherOffset = (rowSize * nextWord) + nextWord;

    char key = keyWord[keyColumn];
    char keyNext = keyWord[keyColumn + keyOffset];

    while (key != cipherText[cipherColumn]) {
        cipherColumn++;
        if (keyNext != cipherText[cipherColumn + cipherOffset]) {
            cipherColumn++;
        }
    }
    return cipherColumn;
}

Lì, ora la logica nel loop è focalizzata su ciò che cambia nel loop. In effetti, tutto tranne cipherColumnpotrebbe essere contrassegnato final. Ehi! Guarda quello. Ora abbiamo spazio per farlo.

Tutto quello che ho fatto è stato aggiungere altre 3 variabili, rinominarne una e riordinarle un po '. E il risultato è appena arrivato a rendere le linee abbastanza corte da adattarsi senza una sciocca interruzione !=.

Sicuramente i nomi keye keyNextnon sono così descrittivi, ma ognuno di essi si abitua solo una volta, non vive così a lungo e, cosa più importante, non sta facendo nulla di così interessante nel ciclo. Quindi non hanno bisogno di essere. Introducendo variabili extra, ora abbiamo spazio per rendere lunghi i loro nomi, se necessario. Le cose cambiano, quindi alla fine potremmo averne bisogno. Se lo facciamo, è bello avere spazio per respirare.

Mi sono anche preso la libertà di mostrarti lo stile variante 6 di Jeff Grigg per la disposizione dei parametri di input per rispettare le restrizioni sulla lunghezza della linea.


Wow, questo è descrittivo! Sì, lo so che il codice non fa davvero nulla, probabilmente avrei dovuto postare più di un piccolo frammento di esso, ma immagino che stavo cercando di ottenere l'idea generale di ciò che i professionisti fanno riguardo alla lunghezza della colonna del codice e ai nomi delle variabili, ma la tua risposta ha mostrato alcuni cambiamenti molto dolci che implementerò sicuramente nei miei codici da ora in poi! Un'altra domanda che ho è: dove lo trovi adatto per fare interruzioni di linea? Prima degli operatori? Esiste uno "standard" accettato?
RaulT

1
@RaulT trascorri un po 'di tempo a leggere qualunque base di codice in cui lavori. Ti darà un'idea di ciò che puoi usare che non sorprenderà gli altri programmatori. Segui un documento sugli standard se ne hai uno. Ma la cosa migliore è chiedere agli altri programmatori e chiedere loro quanto siano leggibili le tue cose. Dai un'occhiata a codereview.stackexchange.com
candied_orange

Vorrei aggiungere un commento sotto cipherOffset e spiegare il calcolo perché quella formula non è ovvia. Dimenticherai perché tra tre settimane.
Nelson,

15

Altri hanno già dato alcuni suggerimenti utili, vorrei riassumere:

  • 80 caratteri per riga potrebbero essere stati una regola d'oro negli anni '80. Oggi la maggior parte delle persone concorda sul fatto che 100-130 caratteri vanno bene.
  • Usa le interruzioni di riga all'interno delle tue espressioni.
  • Dividi lunghe espressioni introducendo risultati intermedi.

Mi piace aggiungere un'altra raccomandazione: non essere dogmatico sui nomi lunghi! Maggiore è l'ambito di una variabile, più informazioni devono essere inserite nel suo nome. E in genere è una buona idea mantenere piccolo l'ambito delle variabili.

Ad esempio, se si dispone di una variabile per la colonna della tabella di crittografia delle parole chiave ed è chiaro che esiste solo questa tabella utilizzata nell'ambito della variabile, è possibile chiamarla columno addirittura col. Se l'ambito è più ampio e ci sono più tabelle coinvolte, ha senso chiamarlo keyWordEncryptionTableColumn.

Un altro esempio: se hai un ciclo con un corpo che si estende su due o tre linee e devi usare un indice per accedere agli elementi di un array, non c'è nulla di sbagliato nel chiamare l'indice i. In questo contesto è molto più leggibile (almeno per la maggior parte delle persone) di, diciamo arrayIndexOfMyVerySpecialDataSet.


1
Sono d'accordo con la tua risposta. Al lavoro utilizziamo 80 caratteri / riga per c / c ++ per motivi legacy e perché utilizziamo la scheda di revisione. Per i caratteri / riga C # 100, a volte ho infranto la regola e vado leggermente oltre i 100 per mantenere la leggibilità.
peval27,

Caspita, che bella risposta !! Tutti questi rispondenti sono stati fantastici, grazie per l'aiuto lo apprezzo!
RaulT

Sono pienamente d'accordo con l'idea che 80 righe di caratteri siano obsolete. Si applica ancora per determinati progetti e luoghi (principalmente per coerenza), ma per molti è semplicemente superfluo. Molti sviluppatori stanno usando qualcosa come Visual Studio o IntelliJ su un monitor completo e hanno un secondo monitor per altre cose (documentazione, ecc.). Hanno quindi un sacco di spazio sullo schermo per il loro codice. Se stai usando solo 80 caratteri per riga, probabilmente hai una tonnellata di spazio inutilizzato. E il limite di 80 caratteri ti fa male! Soprattutto se si considera che la lib standard può forzare nomi di culi lunghi.
Kat

1
Il mio punto è che in alcune lingue, non si può davvero evitare che 80 caratteri rappresentino un grosso limite. Quindi perché averlo inutilmente? Si può anche menzionare che praticamente tutti i grandi editor e IDE hanno in questi giorni un eccellente avvolgimento intelligente delle parole, il che consente di non limitare affatto la lunghezza delle linee. Puoi lasciare che le lunghezze delle linee siano qualsiasi cosa il lettore possa vedere. Possono ridimensionare la finestra per ottenere un risultato più ottimale. Personalmente ho trovato questo approccio a volte ideale. E devo ancora essere deluso da come funziona questo involucro morbido.
Kat

Ogni volta che usi nomi di variabili semplici, DEVI essere sicuro al 100% dell'ambito. Ho trascorso tre ore per conoscere la chiusura di JavaScript.
Nelson,

3

Sono generalmente d'accordo con te insegnante. Tuttavia, se si dispone di una variabile che si intende utilizzare molto in un pezzo di codice di grandi dimensioni non riuscito, può essere meglio utilizzare una forma abbreviata per esso dopo essere stato esplicito sul suo significato. Come quando si hanno molte espressioni e compiti aritmetici complessi, quelli non leggono bene con nomi di variabili lunghe.

A proposito di delineare:

ExtractMessage(char keyWord[25], char cipherText[17424],
               int rowSize, char message[388]) 

Questo non serve a nulla, limitando la lunghezza della linea non lo rende più leggibile. Se vuoi che sia leggibile, fai come segue:

ExtractMessage(
  char keyWord[25],
  char cipherText[17424],
  int rowSize,
  char message[388]
  )
{

E quindi potresti anche voler allineare gli identificatori di tipo (aggiungi uno spazio dopo int). Tuttavia, stai attento / restrittivo nel delineare initalizzazioni o elenchi di argomenti come questo:

int keyColumn    = 0;
int cipherColumn = 0;
int offset       = 1;
int nextWord     = 1;

Il problema è che quando si cambia un nome o si aggiunge una variabile, potrebbe essere necessario riformattare l'intero blocco per mantenere l'aspetto gradevole. Non è per il lavoro tanto quanto per i cambiamenti insignificanti che introduresti, sembrerebbe orribile in un sistema di controllo della versione. Il tuo collega ti vedrebbe modificato il file e fare una diff con la versione precedente per vedere cosa hai fatto. Quindi ogni linea si illuminerebbe come cambiata, oscurando il vero cambiamento. Dipenderebbe un po 'dalla qualità dello strumento di confronto utilizzato quanto questo sarebbe effettivamente negativo, ma in generale non è una buona idea rendere il codice troppo personale e / o far dipendere la formattazione di una riga dall'altra.

A volte delineare può servire a uno scopo, se hai decine di linee consecutive che sono quasi uguali, sarà facile individuare dove sono diverse se le delinei.

Nota che in un ambiente di lavoro potrebbe essere in corso una formattazione automatica che eliminerà qualsiasi formattazione elaborata che esegui nel tuo codice prima di inviarlo al sistema di controllo della versione.


1
Personalmente il primo blocco di codice nella tua risposta è molto più leggibile per me del secondo.
Miles Rout,

1
mai fare il terzo, è un incubo per la manutenzione mantenerlo così.
jwenting

3

Disclaimer: sto esagerando un po 'qui per chiarire il mio punto. Quindi prendi qualsiasi superlativo con un granello di sale.

Il tuo insegnante ha ragione al 100%: non esiste più una "regola d'oro" di circa 80 caratteri (a meno che tu non stia scrivendo codice linux). Quella regola è stata stabilita a causa delle dimensioni dei terminali in quel momento, ma al giorno d'oggi, puoi facilmente riempire oltre 150 caratteri nella finestra del tuo enditor. E anche se superi questo limite, il tuo editor spera di avvolgere delicatamente la linea in modo da non dover scorrere.E l'unica ragione per non andare oltre gli 80 caratteri era la necessità di scorrere .

Detto questo, c'è davvero la necessità di non lasciare che le tue linee crescano indefinitamente. Più lunga è la linea, più diventa difficile per un essere umano analizzare. Ma i nomi di variabili brevi non sono il rimedio al problema delle linee lunghe .

Il rimedio è dividere logicamente le tue espressioni introducendo variabili ancora più correttamente denominate . Non cercare di essere intelligente con gli spazi bianchi. Basta identificare qualsiasi sottoespressione che può essere appropriatamente nominata e creare una variabile per essa. Ciò semplifica sia il codice che calcola la variabile, sia il codice che utilizza quella variabile .


Non fa parte della tua domanda, ma vorrei commentarla comunque: è una pessima idea allineare verticalmente la tua = operatori.

Ci sono tre ragioni per questo:

  1. La modifica di un blocco contenente operatori allineati verticalmente è una PITA. Ogni volta che cambia la lunghezza della variabile più grande (rinomina, aggiunta, cancellazione), è necessario ritoccare tutte le linee nel blocco per ripristinare il layout "bello".

    Naturalmente, questo problema può essere leggermente ridotto usando un editor competente, quindi è la ragione minore. Il vero motivo è il secondo:

  2. Quei cambiamenti spuri negli spazi bianchi introdotti dal riallineamento non giocano bene con i moderni sistemi di controllo della versione come git. Tendono a creare quantità significative di conflitti di unione in cui non si è verificato alcun conflitto reale e in cui nessun conflitto verrebbe segnalato se l'allineamento non fosse utilizzato. Ognuno di questi conflitti spuri ti costerà tempo prezioso per niente .

  3. L'allineamento porta zero significato semantico . È inutile. Non c'è nulla che tu possa capire meglio con l'allineamento. Ogni riga nel tuo blocco deve leggere da sola per capire cosa fa, la connessione con le righe sopra e sotto è di natura puramente sintattica.

Poiché l'allineamento non ha alcun significato semantico, ma produce costi significativi, è necessario disimparare l'abitudine prima che ti costi ancora.


Se ti piace così tanto il limite di 80 caratteri, prova a programmare fortran. È vero, i nuovi standard hanno elevato il limite di fortran a 132 caratteri, ma rimane in vigore come sempre paralizzante la compilazione di qualsiasi programma che superi il limite. Se sei un bravo a programmare, verrai presto ad odiare il fortran, incluso il suo limite di lunghezza della linea. Dopo di ciò, sarai guarito per il resto della tua vita.

Io stesso ho dovuto fare un po 'di programmazione fortran in modo professionale e vi dico che mi ha insegnato a odiare il limite di lunghezza della linea più caro. Non c'è assolutamente nulla di più frustrante che dover dividere una riga altrimenti semplice e leggibile in parti solo perché il compilatore non la compilerà più correttamente. E ci sono sicuramente righe di codice che sono molto semplici quando sono espresse come una singola riga.


3

Molte convenzioni stilistiche (non regole!) Sono sorte nel corso degli anni a causa delle limitazioni negli ambienti di programmazione. Ai tempi delle schede perforate, avevi un forte limite al numero di caratteri che potevano apparire su una linea di origine fisica (motivo per cui Fortran riservava la colonna 6 per i caratteri di continuazione della linea). Non è stato molti decenni fa che stavo lavorando su un terminale VT220 ambra su nero 80x24; mentre gli editor che ho usato non hanno limitato le righe a 80 caratteri, la vita è stata molto più semplice se hai fatto del tuo meglio per evitare lo scorrimento orizzontale.

Nelle versioni precedenti di Fortran (fino al '77, IINM), non potevi nemmeno avere identificatori che fossero lunghi più di 6-8 caratteri. Anche negli anni '80, C avrebbe garantito che i primi 8 caratteri con nomi esterni fossero significativi (motivo per cui alcune funzioni di libreria hanno nomi meravigliosamente descrittivi come strpbrk).

Naturalmente, tra due decenni nel 21 ° secolo, non abbiamo più quei limiti. Non c'è motivo di non utilizzare identificatori più descrittivi.

Il fatto è che, nei contesti giusti, ied je ksono perfettamente ragionevoli, nomi significativi . Se sto ripetendo un array o un vettore in un ciclo e ho solo bisogno di qualcosa per identificare l'elemento corrente, ifunziona perfettamente. Non userei un nome del genere currentElement: non è più significativo in quel contesto e aggiunge solo confusione visiva.

Detto questo, il tuo insegnante non ha torto nel costringerti a pensare in termini di nomi più lunghi e più descrittivi per tutto : la vita sarà più facile per te se prima prendi quell'abitudine e poi impari dove economizzare se necessario. Come qualcuno che è stato un tempo costretto a rientrare tutto in 8 caratteri o meno, è sicuramente meglio sbagliare sul lato della più informazioni rispetto a meno. Man mano che acquisisci più esperienza, imparerai dove puoi risparmiare sulla lunghezza dell'identificatore e dove devi essere un po 'più descrittivo.


-1

Non sono sicuro che funzioni per c oppure no, ma esiste un modo per dividere le formule su più righe? So che esiste qualcosa del genere per Python.

Vedi se riesci a iniziare + (rowSize * nextWord) + nextWord]) {su una nuova riga. (Come premere invio nell'IDE e vedere se lo rientra in modo che C sappia che l'espressione precedente è stata completata sulla riga corrente)


1
Sì, questo è sicuramente possibile. C riconosce le righe e le righe di codice fino a quando non aggiungi qualcosa come un punto e virgola. Il problema è che le nostre funzioni non possono superare le 50 righe e sebbene il mio codice di esempio non contenga 50 righe, è solo una frazione della mia funzione totale. Mi sento pesantemente costretto a scrivere in un riquadro 50 per 80, algoritmi con variabili significative che possono svolgere anche le funzioni di cui ho bisogno. Potrei continuare a memorizzare questi lunghi pezzi di codice in nuove funzioni, ma mi sento come se finissi con così tante chiamate di funzione, le persone si perderanno leggendo il codice.
RaulT

5
"Sento che finirò con così tante chiamate di funzione, le persone si perderanno leggendo il codice." Al contrario! L'estrazione di codice in metodi separati consente di assegnare loro nomi descrittivi aumentando la leggibilità (in particolare del metodo da cui si sta estraendo). Se finisci con troppi metodi la tua classe potrebbe fare molto (principio della responsabilità singola). Estrarre nuovamente i metodi in una classe separata ti consente di dare a quella cosa un nome descrittivo.
Roman Reiner,

Qualsiasi funzione che si avvicina a 50 righe è probabilmente troppo lunga e troppo complessa, (con la possibile eccezione dell'inizializzazione dei dati con una complessità di 1), ma di solito quando si discutono limiti come quelli sono linee di codice e non linee di testo che dividono una singola riga di codice, ovvero al punto e virgola spesso non verrà considerata come una riga aggiuntiva, verificare con il Prof!
Steve Barnes,
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.