CodeGym /Java blog /Véletlen /Kódolási szabályok: a helyes nevek, a jó és rossz megjegy...
John Squirrels
Szint
San Francisco

Kódolási szabályok: a helyes nevek, a jó és rossz megjegyzések ereje

Megjelent a csoportban
Kódolási szabályok: a helyes nevek, a jó és rossz megjegyzések ereje - 1Milyen gyakran kellett beleásnod valaki más kódjába? Két óra helyett két napot tölthet azzal, hogy egyszerűen megértse a történések logikáját. A vicces az, hogy a kódot író személy számára minden világos és teljesen átlátható. Ez nem meglepő: a tökéletes kód végül is nagyon homályos fogalom, mert minden fejlesztőnek megvan a saját elképzelése a világról és a kódról is. Nem egyszer voltam már olyan helyzetben, amikor egy munkatársunkkal ugyanazt a kódot néztük, és eltérő véleményünk volt a helyességéről és tisztaságáról.Kódolási szabályok: a helyes nevek ereje, a jó és rossz megjegyzések - 2Ismerősen hangzik, nem? Ennek ellenére van néhány jól bevált alapelv, amelyet be kell tartani. Végül előnyösek lesznek számodra, mert ha olyan állapotban hagynád a kódodat, ahogyan magad is szeretnéd megkapni, akkor egy kicsit boldogabb és tisztább lesz a világ. Korábbi cikkünkben(vagy inkább kis útmutató) a kódolási szabályokkal kapcsolatban kaptunk egy kis ajánlást a rendszer egészének és alkotórészeinek, például objektumok, interfészek, osztályok, metódusok és változók írására. Ugyanebben a cikkben mellékesen megemlítettem bizonyos elemek helyes elnevezését. Erről szeretnék ma beszélni, mert a helyes elnevezések sokszor könnyebben olvashatóvá teszik a kódot. A helyes kód témáját néhány reflexióval, kis példákkal a kódban található megjegyzésekre és annak mérlegelésével zárjuk, hogy ez jó-e vagy sem. Nos, kezdjük.

Helyes nevek

A helyes elnevezés javítja a kód olvashatóságát, így csökkenti a kóddal való megismerkedés idejét, mivel a metódus használata sokkal könnyebb, ha a neve nagyjából leírja a funkcionalitását. A kódban minden nevekből áll (változók, metódusok, osztályok, objektumok, fájlok stb.), így ez a pont nagyon fontossá válik a helyes, tiszta kód létrehozásánál. A fentiek alapján a névnek jelentést kell közvetítenie, például, hogy miért létezik a változó, mit csinál, és hogyan használják. Nem egyszer megjegyzem, hogy a változóhoz a legjobb megjegyzés az, ha jó nevet adunk neki.Kódolási szabályok: a helyes nevek ereje, a jó és rossz megjegyzések - 3

a "Sherlock" tévésorozatból (2010-2017)

Interfészek elnevezése

Az interfészek nevei általában nagybetűvel kezdődnek, és CamelCase-ben íródnak. Egy interfész írásakor jó gyakorlatnak számított az „I” előtag hozzáadása interfésznek (például IUserService), de ez elég csúnyán és zavaróan néz ki. Ilyen esetekben célszerű elhagyni az előtagot (UserService), és a megvalósítás nevéhez utótagként hozzáadni az "Impl"-t (pl. UserServiceImpl). Vagy végső esetben adjon hozzá egy "C" előtagot az implementáció nevéhez (pl. CUserService).

Osztálynevek

Csakúgy, mint az interfészek, az osztálynevek is nagybetűsek, és CamelCase-t használnak. Nem számít, ha zombiapokalipszissel állunk szemben, nem számít, ha közeleg a vég – soha, soha, soha ne legyen egy osztály neve ige! Az osztály- és objektumneveknek főneveknek vagy összetett főneveknek kell lenniük (UserController, UserDetails, UserAccount és így tovább). Ne ragassza az alkalmazás rövidítését az egyes osztályok nevének végére, mert az csak szükségtelenül bonyolulttá tenné. Például, ha van felhasználói adatáttelepítő alkalmazásunk, akkor kérjük, ne adjon hozzá „UDM”-et minden osztályhoz, azaz UDMUserDetails, UDMUserAccount, UDMUserController.

A módszerek nevei

Általában a metódusnevek kisbetűvel kezdődnek, de használnak tevebetűstílust is (camelCase). Fentebb azt mondtuk, hogy az osztálynevek soha nem lehetnek igék. Itt a helyzet éppen fordított: a metódusok nevei igék vagy igei kifejezések legyenek: findUserById, findAllUsers, createUser stb. A metódusok (valamint a változók és osztályok) létrehozásakor következetes elnevezési konvenciót használjon a félreértések elkerülése érdekében. Például egy felhasználó megtalálásához a metódus neve getUserById vagy findUserById lehet. És még valami: ne használjunk humort a módszerek elnevezésében, mert lehet, hogy mások nem értik a viccet. Ennek eredményeként előfordulhat, hogy nem fogják fel, mit csinál a módszer.

Változónevek

A legtöbb esetben a változónevek kisbetűvel kezdődnek, és a camelCase-t is használják, kivéve, ha a változó globális konstans. Ilyen esetekben a név összes betűjét nagybetűvel írják, és a szavakat aláhúzás ("_") választja el. A kényelem kedvéért értelmes kontextust használhat a változók elnevezésekor. Más szóval, amikor egy változó valami nagyobb dolog részeként létezik, például keresztnév, vezetéknév vagy állapot. Ilyen esetekben hozzáadhat egy előtagot, amely jelzi azt az objektumot, amelyhez ez a változó tartozik. Például: userFirstName, userLastName, userStatus. Kerülje a változók hasonló elnevezését is, ha teljesen eltérő jelentéssel bírnak. Íme néhány gyakran előforduló, változónevekben használt antonim:
  • kezdete/vége
  • Első Utolsó
  • zárva/feloldva
  • minimum maximum
  • következő/előző
  • régi új
  • nyitott/zárt
  • látható/láthatatlan
  • cél forrás
  • a forrás uticélja
  • fel le

Rövid változónevek

Ha olyan változóink vannak, mint az x vagy n, vagy valami hasonló, akkor nem látjuk azonnal a kódot író személy szándékát. Nem nyilvánvaló, hogy n mit csinál. Ennek kitalálása alaposabb elmélkedést igényel (és ez időt, időt, időt jelent). Tegyük fel például, hogy van egy mezőnk, amely a felelős felhasználó azonosítóját képviseli. Valamilyen változónév, például x vagy egyszerűen id helyett ezt a változót "responsibleUserId"-nek nevezzük el, ami azonnal javítja az olvashatóságot és az információtartalmat. Ennek ellenére az olyan rövid neveknek, mint az n, helyi változóként van helye a kis metódusokban, ahol az ezt a változót tartalmazó kódblokk mindössze néhány sor hosszú, és a metódus neve tökéletesen leírja, hogy mi történik ott. Egy ilyen változó láttán a fejlesztő megérti, hogy ez másodlagos jelentőségű, és nagyon korlátozott a hatóköre. Ennek eredményeképpen a hatókör bizonyos mértékben függ a változónév hosszától: minél hosszabb a név, annál globálisabb a változó és fordítva. Példaként egy módszert mutatunk be az utolsó mentett felhasználó dátum szerinti megkeresésére:

public User findLastUser() {
   return findAllUsers().stream()
           .sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
           .findFirst()
           .orElseThrow(() -> new ResourceNotFoundException("No user exists"));
}
Itt a rövid nevű x és y változókat használjuk a folyam rendezésére, majd elfelejtjük őket.

Optimális hosszúság

Folytassuk a névhossz témával. Az optimális névhossz valahol n és maximumNumberOfUsersInTheCurrentGroup között van. Más szóval, a rövid nevek jelentéshiányban szenvednek, míg a túl hosszú nevek meghosszabbítják a programot anélkül, hogy javítanák az olvashatóságot, és egyszerűen lusták vagyunk minden alkalommal leírni őket. A fent leírt esettől eltekintve a rövid nevű változóknál, mint például az n, ragaszkodnia kell a körülbelül 8-16 karakter hosszúsághoz. Ez nem szigorú szabály, csak iránymutatás.

Kis különbségek

Nem hagyhatom figyelmen kívül a nevek finom különbségeit. Ez szintén rossz gyakorlat, mivel ezek a különbségek egyszerűen zavaróak lehetnek, vagy sok extra időt igényelnek észrevételükhöz. Például az InvalidDataAccessApiUsageException és az InvalidDataAccessResourceUsageException közötti különbséget egy pillantással nehéz észrevenni. A kis L és O használatakor is gyakran előfordulhat zavar, mert könnyen összetéveszthetők az 1-gyel és a 0-val. Egyes betűtípusoknál a különbség szembetűnőbb, másoknál kisebb.

A jelentés

A neveket értelmessé kell tennünk, de nem kell kétértelműséget kelteni a szinonimák révén, mivel például a UserData és a UserInfo jelentése valójában ugyanaz. Ebben az esetben mélyebben kell ásnunk a kódban, hogy megértsük, melyik objektumra van szükségünk. Kerülje az olyan szavakat, amelyek nem adnak hasznos információkat. Például a FirstNameString-ben miért van szükségünk a String szóra? Ez tényleg egy dátum objektum? Természetesen nem. Tehát egyszerűen a keresztnevet használjuk. Szeretném megemlíteni a logikai változókat is. Példaként vegyünk egy flagDeleted nevű logikai értéket. A zászló szónak nincs jelentése. Célszerűbb töröltnek nevezni.

Dezinformáció

A helytelen elnevezési szokásokról is szeretnék néhány szót ejteni. Tegyük fel, hogy van egy userActivityList nevű változónk, de ez az objektum Lista helyett valamilyen más tárolótípus vagy egyéni tárolási objektum. Ez megzavarhatja az átlagos programozót: jobb, ha úgy hívjuk, hogy userActivityGroup vagy userActivities.

Keresés

A rövid és egyszerű nevek egyik hátránya, hogy nehéz megtalálni őket egy nagy mennyiségű kódban – Melyiket lenne könnyebb megtalálni: "név" vagy "NAME_FOR_DEFAULT_USER"? A második lehetőség természetesen. Kerüljük a gyakran előforduló szavakat (betűket) a nevekben, mert ezek csak növelik a keresés során az egyező fájlok számát, ami nem jó. Szeretném emlékeztetni, hogy a programozók több időt töltenek a kód olvasásával, mint írásával, ezért ügyeljen az alkalmazás elemeinek elnevezésére. De mi van akkor, ha nem találunk jó nevet? Mi van akkor, ha egy metódus neve nem írja le jól a funkcionalitását? Itt lépnek színre a megjegyzések.

Hozzászólások

Kódolási szabályok: a helyes nevek ereje, a jó és rossz megjegyzések - 4Nincs is jobb egy idevágó megjegyzésnél, de semmi sem zavarja el a modult, mint például az üres, elavult vagy hamis megjegyzések. Kétélű kard lehet, nem? Mégsem kell a megjegyzéseket egyértelműen jóként kezelni, hanem inkább kisebb rosszként. Végtére is, a megjegyzés lényegében egy módja annak, hogy kompenzálja a gondolkodást, amely nem jelenik meg egyértelműen a kódban. Például arra használjuk őket, hogy valahogyan átadjuk egy módszer lényegét, ha maga a módszer túlságosan zavarónak bizonyul. Ebben a helyzetben jobb a kód helyes újrafeldolgozása, mint leíró megjegyzések írása. Minél régebbi a megjegyzés, annál rosszabb a megjegyzés, mert a kód hajlamos növekedni és fejlődni, de a megjegyzések változatlanok maradhatnak. Minél több idő telt el egy megjegyzés létrehozása óta, annál inkább megkérdőjelezhető. A pontatlan megjegyzések sokkal rosszabbak, mint a megjegyzés nélkül, mert zavaróak és megtévesztőek, hamis elvárásokat támasztanak. És még ha nagyon trükkös kódunk is van, inkább írjuk át, mintsem kommenteljük.

A megjegyzések típusai

  • Jogi megjegyzések – Az egyes forrásfájlok elején található megjegyzések jogi okokból, például:

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

  • Tájékoztató megjegyzések – A kód magyarázatát jelentő megjegyzések (kiegészítő információkkal szolgálnak vagy kifejtik egy adott kódrészlet szándékát).

    Például:

    
    /*
    * 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()
           );
           }
    

    Ebben az esetben meg lehet tenni megjegyzések nélkül, hiszen a metódus neve és paraméterei nagyon átlátható funkcionalitással párosulva jól leírják magukat.

  • Figyelmeztető megjegyzések – A megjegyzés célja, hogy figyelmeztesse a többi fejlesztőt egy művelet nemkívánatos következményeire (például figyelmezteti őket arra, hogy egy teszt miért lett @Ignore jelöléssel):

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

  • TODO — Megjegyzések, amelyek olyan dolgokra utalnak, amelyeket a jövőben meg kell tenni, de valamiért most nem lehet megtenni. Ez bevált gyakorlat, de az ilyen megjegyzéseket rendszeresen felül kell vizsgálni a nem releváns megjegyzések eltávolítása és a rendetlenség elkerülése érdekében.

    Egy példa a következő lenne:

    
    // 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);
           }
    

    Itt jegyezzük meg, hogy hozzá kell adnunk a letöltési műveletet végző felhasználó (akinek az azonosítóját a biztonsági kontextusból kinyerjük) összehasonlítását a mentési műveletet végrehajtó felhasználóval.

  • Megerősítő megjegyzések – Olyan megjegyzések, amelyek egy első pillantásra jelentéktelennek tűnő körülmény fontosságát hangsúlyozzák.

    Példaként vegyünk egy olyan módszert, amely kitölti a tesztadatbázist néhány parancsfájllal:

    
    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
    

  • Javadoc megjegyzések – Megjegyzések, amelyek az API-t írják le bizonyos funkciókhoz. Talán itt vannak a leghasznosabb megjegyzések, mivel a dokumentált API-val sokkal könnyebb dolgozni. Ennek ellenére ezek is elavultak lehetnek, mint bármely más típusú megjegyzés. Tehát soha ne felejtsük el, hogy a dokumentációhoz nem a megjegyzések, hanem a jó kód adják a fő hozzájárulást.

    Íme egy példa egy meglehetősen gyakori módszerre a felhasználó frissítésére:

    
    /**
    * 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);
    

Rossz kommentek

  • motyogó megjegyzés — Olyan megjegyzések, amelyeket általában sietve írnak, és amelyek jelentését csak az azt író fejlesztő érti, mivel csak ő érzékeli azt az árnyalt helyzetet, amelyre a megjegyzés vonatkozik.

    Tekintsük ezt a példát:

    
    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 
          }
    }
    

    Ki tölti be ezeket a beállításokat? Fel lettek töltve már? Ennek a módszernek el kell fogadnia a kivételeket és betöltenie az alapértelmezett beállításokat? Túl sok kérdés merül fel, amelyekre csak a rendszer más részeinek vizsgálatával lehet választ adni.

  • Redundáns megjegyzések – olyan megjegyzések, amelyek nem hordoznak semmilyen szemantikai terhelést, mivel teljesen világos, hogy mi történik a kód adott szakaszában. Más szóval, a megjegyzés nem olvasható könnyebben, mint a kód.

    Lássunk egy példát:

    
    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;
       }
    

    Mi értelme van az ilyen kommenteknek? Minden, amit elmagyaráznak, már teljesen világos.

  • Megbízhatatlan megjegyzések — Valótlan és csak félrevezető megjegyzések (dezinformáció). Például itt van egy.

    
    /**
    * 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();
    }
    

    Mi a baj ezzel a megjegyzéssel? Az, hogy egy kicsit hazudik nekünk, hogy a kapcsolat megszakad, ha isNotUsing hamis, nem pedig fordítva, ahogy a megjegyzés tájékoztat.

  • Kötelező megjegyzések — Kötelezőnek tekintett megjegyzések (pl. Javadoc megjegyzések), de valójában néha túlságosan felhalmozódnak, és megbízhatatlanok és szükségtelenek (el kell gondolkodni, hogy ezekre a megjegyzésekre valóban szükség van-e).

  • Példa:

    
    /**
    * 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);
    

    Megértenéd, mit csinál a módszer e megjegyzések nélkül? Valószínűleg igen, így a megjegyzések itt értelmetlenné válnak.

  • Megjegyzések naplózása — Megjegyzések, amelyek néha a modul elejére kerülnek minden szerkesztéskor (olyan, mint egy változásnapló).

    
    /**
    * 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;
    */
    

    Ez a megközelítés egykor indokolt volt, de a verziókövető rendszerek (például a Git) megjelenésével a kód szükségtelen zsúfoltságává és bonyodalmává vált.

  • Szerzőségi megjegyzések — Olyan megjegyzések, amelyek célja a kódot író személy feltüntetése, hogy kapcsolatba léphessen vele, és megvitassák, hogyan, mit és miért, pl.

    
    * @author Bender Bending
    

    A verziókezelő rendszerek ismét pontosan emlékeznek arra, hogy ki és mikor adott hozzá egy kódrészletet, ezért ez a megközelítés felesleges.

  • Kommentált kód – olyan kód, amelyet valamilyen okból kijegyeztek. Ez az egyik legrosszabb szokás, mert az történik, hogy valamit kommentelsz és elfelejtesz, aztán a többi fejlesztőnek nincs bátorsága törölni (végül is, mi van, ha valami értékes?).

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

    Ennek eredményeként a kommentált kódok úgy gyűlnek össze, mint a szemét. Semmi esetre se hagyjon ilyen kódot. Ha valóban szüksége van rá, ne feledkezzen meg a verziókezelő rendszerről.

  • Nem nyilvánvaló megjegyzések – olyan megjegyzések, amelyek valamit túlságosan bonyolultan írnak le.

    
    /*
        * 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];
    

    A kódot egy megjegyzésnek kell elmagyaráznia. Ez önmagában nem igényel magyarázatot. Szóval mi a baj itt? Mik azok a "szűrő bájtok"? Miről szól ez a "+1"? Miért pont 300?

Ha már úgy döntött, hogy megjegyzéseket ír, íme néhány tipp:
  1. Használjon könnyen karbantartható stílusokat: a túl divatos és egzotikus stílusok fenntartása bosszantó és időigényes.
  2. Ne használjon sorvégi megjegyzéseket, amelyek egyetlen sorra utalnak: az eredmény egy nagy halom megjegyzés. Ráadásul nehéz minden sorhoz értelmes megjegyzést kitalálni.
  3. Amikor megjegyzést ír, próbáljon a „miért” kérdésre válaszolni, ne a „hogyan” kérdésre.
  4. Kerülje a rövidített információkat. Ahogy fentebb is mondtam, egy megjegyzéshez nincs szükségünk magyarázatra: a megjegyzés maga a magyarázat.
  5. Megjegyzések segítségével feljegyezheti a mértékegységeket és az értéktartományokat.
  6. A megjegyzéseket az általuk leírt kód közelében helyezze el.
Végezetül még mindig szeretném emlékeztetni, hogy a legjobb megjegyzés a megjegyzés hiánya, hanem az ügyes elnevezés alkalmazása az alkalmazás során. Általános szabály, hogy legtöbbször meglévő kóddal dolgozunk, karbantartjuk és bővítjük azt. Sokkal kényelmesebb, ha ez a kód könnyen olvasható és érthető, mivel a rossz kód akadályt jelent. Olyan ez, mint egy csavarkulcsot a munkába dobni, és a sietség hűséges társa. És minél több rossz kódunk van, annál jobban csökken a teljesítmény. Ez azt jelenti, hogy időről időre át kell alakítanunk. De ha a kezdetektől fogva megpróbál olyan kódot írni, amely miatt a következő fejlesztők nem akarnak megtalálni és megölni, akkor nem kell olyan gyakran újrafaktorálnia. De továbbra is szükség lesz rá, mivel a termék feltételei és követelményei folyamatosan változnak az új függőségek és kapcsolatok megjelenésével. Nos, azt hiszem, nekem mára ennyi. Köszönöm mindenkinek aki idáig elolvasta :)
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION