CodeGym /Java Blog /Random-IT /Regole di codifica: il potere dei nomi corretti, dei comm...
John Squirrels
Livello 41
San Francisco

Regole di codifica: il potere dei nomi corretti, dei commenti positivi e negativi

Pubblicato nel gruppo Random-IT
Regole di codifica: il potere dei nomi corretti, dei commenti positivi e negativi - 1Quante volte hai dovuto scavare nel codice di qualcun altro? Invece di due ore, potresti dedicare due giorni per capire semplicemente la logica di ciò che sta accadendo. La cosa buffa è che per chi ha scritto il codice tutto è chiaro e del tutto trasparente. La cosa non sorprende: in fondo, codice perfetto è un concetto molto vago, perché ogni sviluppatore ha la propria visione del mondo e anche del codice. Più di una volta mi sono trovato in una situazione in cui io e un collega abbiamo guardato lo stesso codice e avevamo opinioni diverse sulla sua correttezza e pulizia.Regole di codifica: il potere dei nomi corretti, dei commenti positivi e negativi - 2Suona familiare, vero? Tuttavia, ci sono alcuni principi testati nel tempo che dovrebbero essere rispettati. Alla fine, saranno vantaggiosi per te, perché se lasci il tuo codice nello stato in cui tu stesso vorresti riceverlo, allora il mondo diventerebbe un po' più felice e pulito. Nel nostro precedente articolo(o meglio, piccola guida) sulle regole di codifica, abbiamo avuto un piccolo senso delle raccomandazioni per scrivere un sistema nel suo insieme e le sue parti costituenti, come oggetti, interfacce, classi, metodi e variabili. In quello stesso articolo, ho citato casualmente la corretta denominazione di alcuni elementi. Vorrei parlarne oggi, perché i nomi corretti rendono il codice molte volte più facile da leggere. Chiuderemo l'argomento del codice corretto con alcune riflessioni, piccoli esempi di commenti nel codice e una considerazione se questo è buono o meno. Bene, cominciamo.

Nomi corretti

I nomi corretti migliorano la leggibilità del codice, riducendo così il tempo necessario per familiarizzare con il codice, perché l'utilizzo di un metodo è molto più semplice quando il suo nome ne descrive approssimativamente la funzionalità. Tutto nel codice è costituito da nomi (variabili, metodi, classi, oggetti, file, ecc.), quindi questo punto diventa molto importante quando si crea un codice corretto e pulito. Sulla base di quanto sopra, il nome dovrebbe trasmettere un significato, ad esempio, perché la variabile esiste, cosa fa e come viene utilizzata. Noterò più di una volta che il miglior commento per una variabile è darle un buon nome.Regole di codifica: il potere dei nomi corretti, dei commenti positivi e negativi - 3

dalla serie TV "Sherlock" (2010-2017)

Interfacce di denominazione

Le interfacce di solito hanno nomi che iniziano con una lettera maiuscola e sono scritte in CamelCase. Quando si scriveva un'interfaccia, era considerata una buona pratica aggiungere il prefisso "I" per designarla come interfaccia (ad esempio, IUserService), ma sembra piuttosto brutto e fonte di distrazione. In questi casi, è meglio omettere il prefisso (UserService) e aggiungere "Impl" come suffisso al nome della sua implementazione (es. UserServiceImpl). O possibilmente, come ultima risorsa, aggiungi un prefisso "C" al nome dell'implementazione (es. CUserService).

Nomi di classe

Proprio come le interfacce, i nomi delle classi sono in maiuscolo e usano CamelCase. Non importa se stiamo affrontando un'apocalisse di zombi, non importa se la fine è vicina: mai, mai, mai il nome di una classe dovrebbe essere un verbo! I nomi delle classi e degli oggetti devono essere nomi o nomi composti (UserController, UserDetails, UserAccount e così via). Non dovresti aggiungere l'abbreviazione dell'applicazione alla fine del nome di ogni classe, poiché ciò aggiungerebbe solo complessità non necessaria. Ad esempio, se disponiamo di un'applicazione di migrazione dei dati utente, non aggiungere "UDM" a ciascuna classe, ad esempio UDMUserDetails, UDMUserAccount, UDMUserController.

Nomi dei metodi

Di solito, i nomi dei metodi iniziano con una lettera minuscola, ma usano anche lo stile camel case (camelCase). Sopra, abbiamo detto che i nomi delle classi non dovrebbero mai essere verbi. Qui la situazione è esattamente l'opposto: i nomi dei metodi dovrebbero essere verbi o frasi verbali: findUserById, findAllUsers, createUser e così via. Quando crei un metodo (oltre a variabili e classi), utilizza una convenzione di denominazione coerente per evitare confusione. Ad esempio, per trovare un utente, un metodo potrebbe essere denominato getUserById o findUserById. E ancora una cosa: non usare l'umorismo nei nomi dei metodi, perché gli altri potrebbero non capire lo scherzo. Di conseguenza, potrebbero non riuscire a capire cosa fa il metodo.

Nomi variabili

Nella maggior parte dei casi, i nomi delle variabili iniziano con una lettera minuscola e usano anche camelCase, tranne quando la variabile è una costante globale. In tali casi, tutte le lettere del nome sono scritte in maiuscolo e le parole sono separate da un carattere di sottolineatura ("_"). Per comodità, puoi usare un contesto significativo quando dai un nome alle variabili. In altre parole, quando una variabile esiste come parte di qualcosa di più grande, ad esempio firstName, lastName o status. In tali casi, è possibile aggiungere un prefisso che indichi l'oggetto a cui appartiene questa variabile. Ad esempio: userFirstName, userLastName, userStatus. Dovresti anche evitare nomi simili per le variabili quando hanno significati completamente diversi. Ecco alcuni contrari che si incontrano di frequente nei nomi delle variabili:
  • inizio/fine
  • primo ultimo
  • bloccato/sbloccato
  • minimo Massimo
  • successivo/precedente
  • vecchio nuovo
  • aperto/chiuso
  • visibile/invisibile
  • sorgente/destinazione
  • cerca la destinazione
  • sottosopra

Nomi brevi di variabili

Quando abbiamo variabili come x o n o qualcosa del genere, non vediamo immediatamente l'intento della persona che ha scritto il codice. Non è ovvio cosa fa n. Capirlo richiede una contemplazione più attenta (e questo significa tempo, tempo, tempo). Ad esempio, supponiamo di avere un campo che rappresenta l'id dell'utente responsabile. Invece di un nome di variabile come x o semplicemente id, chiameremo questa variabile "responsibleUserId", che migliora immediatamente la leggibilità e il contenuto delle informazioni. Detto questo, nomi brevi come n hanno un posto come variabili locali in metodi piccoli, dove il blocco di codice che coinvolge questa variabile è lungo solo un paio di righe e il nome del metodo descrive perfettamente cosa succede lì. Vedendo una tale variabile, uno sviluppatore capisce che è di secondaria importanza e ha una portata molto limitata. Di conseguenza, l'ambito ha una certa dipendenza dalla lunghezza del nome di una variabile: più lungo è il nome, più globale è la variabile e viceversa. Ad esempio, ecco un metodo per trovare l'ultimo utente salvato per data:

public User findLastUser() {
   return findAllUsers().stream()
           .sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
           .findFirst()
           .orElseThrow(() -> new ResourceNotFoundException("No user exists"));
}
Qui usiamo variabili con nomi brevi x e y per ordinare il flusso, e poi ce ne dimentichiamo.

Lunghezza ottimale

Continuiamo con l'argomento della lunghezza del nome. La lunghezza ottimale del nome è compresa tra n e maximumNumberOfUsersInTheCurrentGroup. In altre parole, i nomi brevi soffrono di una mancanza di significato, mentre i nomi troppo lunghi allungano il programma senza aggiungere leggibilità, e siamo semplicemente troppo pigri per scriverli ogni volta. A parte il caso descritto sopra per le variabili con un nome breve come n, dovresti attenersi a una lunghezza di circa 8-16 caratteri. Questa non è una regola rigida, solo una linea guida.

Piccole differenze

Non posso non menzionare sottili differenze nei nomi. Questa è anche una cattiva pratica, poiché queste differenze possono semplicemente creare confusione o richiedere molto tempo in più per notarle. Ad esempio, la differenza tra InvalidDataAccessApiUsageException e InvalidDataAccessResourceUsageException è difficile da individuare a colpo d'occhio. Spesso può sorgere confusione anche quando si usano L e O minuscole, perché possono essere facilmente scambiate per 1 e 0. In alcuni font la differenza è più evidente, in altri meno.

Il significato

Dobbiamo rendere i nomi significativi, ma non creare ambiguità attraverso sinonimi, poiché, ad esempio, UserData e UserInfo hanno effettivamente lo stesso significato. In questo caso, dovremmo scavare più a fondo nel codice per capire di quale particolare oggetto abbiamo bisogno. Evita parole che non trasmettono informazioni utili. Ad esempio, in firstNameString, perché abbiamo bisogno della parola String? Potrebbe davvero essere un oggetto Date? Ovviamente no. Quindi, usiamo semplicemente firstName. Vorrei anche menzionare le variabili booleane. Ad esempio, prendi un booleano chiamato flagDeleted. La parola bandiera non ha significato. È più ragionevole chiamarlo isDeleted.

Disinformazione

Vorrei anche spendere alcune parole sulle convenzioni di denominazione errate. Supponiamo di avere una variabile denominata userActivityList, ma invece di essere un elenco, questo oggetto è un altro tipo di contenitore o un oggetto di archiviazione personalizzato. Questo potrebbe confondere il programmatore medio: è meglio chiamarlo qualcosa come userActivityGroup o userActivities.

Ricerca

Uno degli svantaggi dei nomi brevi e semplici è che sono difficili da trovare in un ampio corpo di codice — Quale sarebbe più facile da trovare: "name" o "NAME_FOR_DEFAULT_USER"? La seconda opzione, ovviamente. Dovremmo evitare le parole (lettere) incontrate di frequente nei nomi, poiché aumenteranno solo il numero di file corrispondenti durante una ricerca, il che non va bene. Vorrei ricordarti che i programmatori passano più tempo a leggere il codice che a scriverlo, quindi sii intelligente nel nominare gli elementi della tua applicazione. Ma cosa succede se non si riesce a trovare un buon nome? Cosa succede se il nome di un metodo non descrive bene la sua funzionalità? È qui che entrano in scena i commenti.

Commenti

Regole di codifica: il potere dei nomi corretti, dei commenti positivi e negativi - 4Non c'è niente di meglio di un commento pertinente, ma niente ingombra un modulo come commenti vacui, obsoleti o falsi. Possono essere un'arma a doppio taglio, no? Tuttavia, non dovresti trattare i commenti come inequivocabilmente buoni, ma piuttosto come un male minore. Dopotutto, un commento è essenzialmente un modo per compensare il pensiero che non emerge chiaramente nel codice. Ad esempio, li usiamo per trasmettere in qualche modo l'essenza di un metodo, se il metodo stesso risulta essere troppo confuso. In questa situazione, è meglio eseguire correttamente il refactoring del codice piuttosto che scrivere note descrittive. Più vecchio è il commento, peggiore è il commento, perché il codice tende a crescere ed evolversi, ma i commenti possono rimanere gli stessi. Più tempo è passato da quando è stato creato un commento, più questo può essere discutibile. I commenti imprecisi sono molto peggio di nessun commento, perché sono confusi e ingannevoli, dando false aspettative. E anche se abbiamo un codice molto complicato, dovremmo riscriverlo piuttosto che commentarlo.

Tipi di commenti

  • Commenti legali : commenti all'inizio di ogni file di origine per motivi legali, ad esempio:

    
    * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
    * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
    

  • Commenti informativi — Commenti che rappresentano una spiegazione del codice (fornendo informazioni aggiuntive o esponendo l'intenzione di una data sezione del codice).

    Per esempio:

    
    /*
    * Combines the user from the database with the one passed for updating
    * When a field in requestUser is empty, it is filled with old data from foundUser
    */
    private User mergeUser(User requestUser, User foundUser) {
           return new User(
           foundUser.getId(),
           requestUser.getFirstName() == null ? requestUser.getFirstName() : foundUser.getFirstName(),
           requestUser.getMiddleName() == null ? requestUser.getMiddleName() : foundUser.getMiddleName(),
           requestUser.getLastName() == null ? requestUser.getLastName() : foundUser.getLastName(),
           requestUser.getAge() == null ? requestUser.getAge() : foundUser.getAge()
           );
           }
    

    In questo caso si può fare a meno dei commenti, poiché il nome del metodo ei suoi parametri, insieme a funzionalità molto trasparenti, si descrivono bene.

  • Commenti di avviso : commento inteso ad avvertire altri sviluppatori delle conseguenze indesiderabili di un'azione (ad esempio, avvisandoli del motivo per cui un test è stato contrassegnato come @Ignore):

    
    // Takes too long to run
    // Don't run if you don't have a lot of time
    @Ignore
    @Test
    public void someIntegrationTest() {
           ……
           }
    

  • TODO — Commenti che sono una nota su qualcosa che deve essere fatto in futuro ma che per qualche motivo non può essere fatto ora. Questa è una buona pratica, ma tali commenti dovrebbero essere rivisti regolarmente per rimuovere quelli irrilevanti ed evitare confusione.

    Un esempio potrebbe essere:

    
    // TODO: Add a check for the current user ID (when the security context is created)
    
    @Override
    public Resource downloadFile(File file) {
           return fileManager.download(file);
           }
    

    Qui notiamo il fatto che dobbiamo aggiungere un confronto tra l'utente che esegue l'operazione di download (di cui estrarremo l'ID dal contesto di sicurezza) con quello che ha eseguito l'operazione di salvataggio.

  • Commenti di rinforzo — Commenti che sottolineano l'importanza di una circostanza che a prima vista può sembrare insignificante.

    Ad esempio, considera una parte di un metodo che riempie un database di test con alcuni script:

    
    Stream.of(IOUtils.resourceToString("/fill-scripts/" + x, StandardCharsets.UTF_8)
           .trim()
           .split(";"))
           .forEach(jdbcTemplate::update);
    // The trim() call is very important. It removes possible spaces at the end of the script
    // so that when we read and split into separate requests, we don't end up with empty ones
    

  • Commenti Javadoc : commenti che descrivono l'API per determinate funzionalità. Ci sono probabilmente i commenti più utili, poiché è molto più facile lavorare con l'API documentata. Detto questo, possono anche essere obsoleti come qualsiasi altro tipo di commento. Quindi, non dimenticare mai che il principale contributo alla documentazione non è dato dai commenti, ma da un buon codice.

    Ecco un esempio di un metodo abbastanza comune per aggiornare un utente:

    
    /**
    * Updates the passed fields for a user based on its id.
         *
    * @param id id of the user to be updated
    * @param user user with populated fields for updating
    * @return updated user
    */
           User update(Long id, User user);
    

Commenti negativi

  • borbottando commento — Commenti che di solito vengono scritti in fretta e il cui significato è comprensibile solo allo sviluppatore che li ha scritti, poiché solo lui o lei percepisce la situazione sfumata a cui si riferisce il commento.

    Considera questo esempio:

    
    public void configureSomeSystem() {
           try{
           String configPath = filesLocation.concat("/").concat(CONFIGURATION_FILE);
           FileInputStream stream = new FileInputStream(configPath);
           } catch (FileNotFoundException e) {
           // If there is no configuration file, the default configuration is loaded 
          }
    }
    

    Chi carica queste impostazioni? Sono già stati caricati? Questo metodo dovrebbe rilevare le eccezioni e caricare le impostazioni predefinite? Sorgono troppe domande a cui si può rispondere solo approfondendo un'indagine su altre parti del sistema.

  • Commenti ridondanti : commenti che non comportano alcun carico semantico, poiché ciò che sta accadendo in una data sezione del codice è abbondantemente chiaro. In altre parole, il commento non è più facile da leggere del codice.

    Vediamo un esempio:

    
    public class JdbcConnection{
    public class JdbcConnection{
       /**
        * The logger associated with the current class
        */
       private Logger log = Logger.getLogger(JdbcConnection.class.getName());
    
       /**
        * Creates and returns a connection using the input parameters
        */
       public static Connection buildConnection(String url, String login, String password, String driver) throws Exception {
           Class.forName(driver);
           connection = DriverManager.getConnection(url, login, password);
           log.info("Created connection with db");
           return connection;
       }
    

    Qual è il punto di tali commenti? Tutto ciò che spiegano è già perfettamente chiaro.

  • Commenti inaffidabili : commenti falsi e solo fuorvianti (disinformazione). Ad esempio, eccone uno.

    
    /**
    * Helper method. Closes the connection with the scanner if isNotUsing is true
    */
    private void scanClose(Scanner scan, boolean isNotUsing) throws Exception {
       if (!isNotUsing) {
           throw new Exception("The scanner is still in use");
       } scan.close();
    }
    

    Cosa c'è di sbagliato in questo commento? Il fatto che ci menta un po', in quanto la connessione viene chiusa se isNotUsing è falso, non viceversa, come ci informa il commento.

  • Commenti obbligatori — Commenti considerati obbligatori (ad es. commenti Javadoc), ma che in realtà a volte si accumulano eccessivamente e sono inaffidabili e non necessari (bisogna pensare se questi commenti sono effettivamente necessari).

  • Esempio:

    
    /**
    * Create a user based on the parameters
    * @param firstName first name of the created user
    * @param middleName middle name of the created user
    * @param lastName last name of the created user
    * @param age age of the created user
    * @param address address of the created user
    * @return user that was created
    */
    User createNewUser(String firstName, String middleName, String lastName, String age, String address);
    

    Saresti in grado di capire cosa fa il metodo senza questi commenti? Molto probabilmente sì, quindi i commenti qui diventano inutili.

  • Commenti del registro : commenti che a volte vengono aggiunti all'inizio di un modulo ogni volta che viene modificato (qualcosa come un registro delle modifiche).

    
    /**
    * Records kept since January 9, 2020;
    **********************************************************************
    * 9 Jan 2020: Providing a database connection using JDBC Connection;
    * 15 Jan 2020: Adding DAO-level interfaces for working with the database;
    * 23 Jan 2020: Adding integration tests for the database;
    * 28 Jan 2020: Implementation of DAO-level interfaces;
    * 1 Feb 2020: Development of interfaces for services,
    * in accordance with the requirements specified in user stories;
    * 16 Feb 2020: Implementation of service interfaces
    * (implementation of business logic related to the work of the database);
    * 25 Feb 2020: Adding tests for services;
    * 8 Mar 2020: Celebration of International Women's Day (Terry is drunk again);
    * 21 Mar 2020: Refactoring the service layer;
    */
    

    Questo approccio una volta era giustificato, ma con l'avvento dei sistemi di controllo della versione (ad esempio Git) è diventato un inutile disordine e complicazione del codice.

  • Commenti sull'autore — Commenti il ​​cui scopo è indicare la persona che ha scritto il codice, in modo da poterla contattare e discutere come, cosa e perché, ad esempio:

    
    * @author Bender Bending
    

    Ancora una volta, i sistemi di controllo della versione ricordano esattamente chi ha aggiunto qualsiasi bit di codice e quando, quindi questo approccio è superfluo.

  • Codice commentato : codice che è stato commentato per un motivo o per l'altro. Questa è una delle peggiori abitudini, perché quello che succede è commentare qualcosa e dimenticarlo, e poi gli altri sviluppatori semplicemente non hanno il coraggio di cancellarlo (dopotutto, e se fosse qualcosa di prezioso?).

    
    //    public void someMethod(SomeObject obj) {
    //    .....
    //    }
    

    Di conseguenza, il codice commentato si accumula come spazzatura. In nessun caso dovresti lasciare tale codice. Se ne hai davvero bisogno, non dimenticare il sistema di controllo della versione.

  • Commenti non ovvi : commenti che descrivono qualcosa in modo eccessivamente complicato.

    
    /*
        * Start with an array large enough to store
        * all the data bytes (plus filter bytes) with a cushion, plus 300 bytes
        * for header data
        */
    this.dataBytes = new byte[(this.size * (this.deep + 1) * 2)+300];
    

    Un commento dovrebbe spiegare il codice. Non dovrebbe di per sé aver bisogno di una spiegazione. Quindi cosa c'è che non va qui? Cosa sono i "byte filtro"? Cos'è quel "+1"? Perché esattamente 300?

Se hai già deciso di scrivere commenti, ecco un paio di suggerimenti:
  1. Usa stili facili da mantenere: mantenere stili troppo fantasiosi ed esotici è fastidioso e richiede tempo.
  2. Non utilizzare commenti di fine riga che si riferiscono a singole righe: il risultato è una grande pila di commenti. Inoltre, è difficile pensare a un commento significativo per ogni riga.
  3. Quando componi un commento, prova a rispondere alla domanda "perché", non "come".
  4. Evitare informazioni abbreviate. Come ho detto sopra, non abbiamo bisogno di una spiegazione per un commento: il commento stesso è la spiegazione.
  5. È possibile utilizzare i commenti per prendere nota delle unità e degli intervalli di valori.
  6. Posiziona i commenti vicino al codice che descrivono.
Infine, voglio ancora ricordarti che il miglior commento non è un commento, ma piuttosto l'uso di nomi abili in tutta la tua applicazione. Di norma, la maggior parte delle volte lavoreremo con il codice esistente, mantenendolo ed estendendolo. È molto più conveniente quando questo codice è facile da leggere e comprensibile, poiché il codice errato è un ostacolo. È come gettare una chiave inglese nelle opere, e la fretta è la sua fedele compagna. E più cattivo codice abbiamo, più diminuiscono le prestazioni. Ciò significa che dobbiamo eseguire il refactoring di tanto in tanto. Ma se fin dall'inizio provi a scrivere codice che non farà sì che i prossimi sviluppatori vogliano trovarti e ucciderti, allora non avrai bisogno di refactoring così spesso. Ma sarà comunque necessario, poiché le condizioni ei requisiti del prodotto cambiano costantemente con l'aggiunta di nuove dipendenze e connessioni. Beh, immagino sia tutto per me oggi. Grazie a tutti quelli che hanno letto fino a qui :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION