Rens kodning i Java
1. Oversigt
I denne vejledning gennemgår vi rene kodningsprincipper. Vi forstår også, hvorfor ren kode er vigtig, og hvordan man opnår det i Java. Yderligere vil vi se, om der er værktøjer til rådighed, der kan hjælpe os.
2. Hvad er ren kode?
Så før vi hopper ind i detaljerne i ren kode, lad os forstå, hvad vi mener med ren kode. Ærligt talt kan der ikke være et godt svar på dette. I programmeringen når nogle bekymringer ud og resulterer derfor i generelle principper. Men så præsenterer hvert programmeringssprog og paradigme deres eget sæt nuancer, som giver os mandat til at vedtage passende praksis.
Bredt, ren kode kan sammenfattes som en kode, som enhver udvikler let kan læse og ændre. Selvom dette måske lyder som en overforenkling af konceptet, ser vi senere i vejledningen, hvordan dette bygger op. Overalt hvor vi hører om ren kode, støder vi måske på en eller anden henvisning til Martin Fowler. Sådan beskriver han ren kode et af stedene:
Enhver fjols kan skrive kode, som en computer kan forstå. Gode programmører skriver kode, som mennesker kan forstå.
3. Hvorfor skal vi være interesserede i ren kode?
At skrive ren kode er et spørgsmål om personlig vane så meget som det handler om dygtighed. Som udvikler vokser vi gennem erfaring og viden over tid. Men vi må spørge, hvorfor vi trods alt skal investere i at udvikle ren kode? Vi får, at andre sandsynligvis har lettere ved at læse vores kode, men er det incitament nok? Lad os finde ud af det!
Rene kodningsprincipper hjælper os med at nå mange ønskelige mål relateret til den software, vi har til hensigt at producere. Lad os gennemgå dem for at forstå det bedre:
- Vedligeholdelig kodebase: Al software, som vi udvikler, har en produktiv levetid og i denne periode kræver ændringer og generel vedligeholdelse. Rens kode kan hjælpe med at udvikle software, der er let at ændre og vedligeholde over tid.
- Lettere fejlfinding: Software kan udvise utilsigtet adfærd på grund af en række interne eller eksterne faktorer. Det kan ofte kræve en hurtig vending med hensyn til rettelser og tilgængelighed. Software udviklet med rene kodningsprincipper er lettere at foretage fejlfinding for problemer.
- Hurtigere ombordstigning: Software i løbet af dens levetid vil se, at mange udviklere opretter, opdaterer og vedligeholder den, hvor udviklere deltager på forskellige tidspunkter. Dette kræver en hurtigere ombordstigning for at holde produktiviteten højog ren kode hjælper med at nå dette mål.
4. Karakteristika ved ren kode
Kodebaser skrevet med rene kodningsprincipper udviser flere egenskaber, der adskiller dem. Lad os gennemgå nogle af disse egenskaber:
- Fokuseret: Et stykke kode skal skrives for at løse et specifikt problem. Det bør ikke gøre noget, der strengt taget ikke er relateret til at løse det givne problem. Dette gælder for alle abstraktionsniveauer i kodebasen som metode, klasse, pakke eller modul.
- Enkel: Dette er langt den vigtigste og ofte ignoreret egenskab ved ren kode. Softwaren design og implementering skal være så simpelt som muligt, som kan hjælpe os med at opnå de ønskede resultater. Øget kompleksitet i en codebase gør dem fejlbehæftede og vanskelige at læse og vedligeholde.
- Testbar: Ren kode, selvom den er enkel, skal løse det aktuelle problem. Det må være intuitiv og let at teste kodebasen, fortrinsvis på en automatiseret måde. Dette hjælper med at etablere kodebasens grundlæggende opførsel og gør det lettere at ændre den uden at bryde noget.
Det er det, der hjælper os med at nå de mål, der blev diskuteret i det foregående afsnit. Det er en fordel at begynde at udvikle sig med disse egenskaber i tankerne sammenlignet med refaktor senere. Dette fører til lavere samlede ejeromkostninger for softwarelevecyklussen.
5. Rens kodning i Java
Nu hvor vi har gennemgået nok baggrund, lad os se, hvordan vi kan indarbejde rene kodningsprincipper i Java. Java tilbyder mange bedste fremgangsmåder, der kan hjælpe os med at skrive ren kode. Vi kategoriserer dem i forskellige spande og forstår, hvordan man skriver ren kode med kodeeksempler.
5.1. Projektstruktur
Mens Java ikke håndhæver nogen projektstruktur, Det er altid nyttigt at følge et ensartet mønster for at organisere vores kildefiler, test, konfigurationer, data og andre kodeartefakter. Maven, et populært byggeværktøj til Java, foreskriver en bestemt projektstruktur. Selvom vi muligvis ikke bruger Maven, er det altid rart at holde os til en konvention.
Lad os se nogle af de mapper, som Maven foreslår, at vi opretter:
- src / main / java: Til kildefiler
- src / main / ressourcer: Til ressourcefiler, som egenskaber
- src / test / java: Til testkildefiler
- src / test / ressourcer: Til testressourcefiler, som egenskaber
I lighed med dette er der andre populære projektstrukturer som Bazel foreslået til Java, og vi bør vælge en afhængig af vores behov og publikum.
5.2. Navngivningskonvention
Følge navngivningskonventioner kan gå langt med at gøre vores kode læsbar og dermed vedligeholdelig. Rod Johnson, skaberen af Spring, understreger vigtigheden af at navngive konventioner om foråret:
“... hvis du ved hvad noget gør, har du en ret god chance for at gætte navnet på Spring Class eller interface til det ...”
Java ordinerer et sæt regler, som skal overholdes, når det kommer til at navngive noget i Java. Et velformet navn hjælper ikke kun med at læse koden, men det formidler også meget om kodens hensigt. Lad os tage nogle eksempler:
- Klasser: Klasse med hensyn til objektorienterede begreber er en plan for objekter, der ofte repræsenterer objekter i den virkelige verden. Derfor er det meningsfuldt at bruge substantiver til at navngive klasser, der beskriver dem tilstrækkeligt:
offentlig klasse kunde {}
- Variabler: Variabler i Java fanger tilstanden for det objekt, der er oprettet fra en klasse. Navnet på variablen skal klart beskrive hensigten med variablen:
offentlig klasse kunde {privat streng kunde navn; }
- Metoder: Metoder i Java er altid en del af klasser og repræsenterer derfor generelt en handling på objektets tilstand oprettet fra klassen. Det er derfor nyttigt at navngive metoder ved hjælp af verb:
offentlig klasse kunde {privat streng kunde navn; public String getCustomerName () {returner this.customerName; }}
Mens vi kun har diskuteret, hvordan man navngiver en identifikator i Java, skal du være opmærksom på, at der er yderligere bedste praksis som kamelhylster, som vi skal overholde for læsbarhed. Der kan være flere konventioner relateret til navngivning af grænseflader, enums, konstanter også.
5.3. Kildefilstruktur
En kildefil kan indeholde forskellige elementer. Mens Java kompilatoren håndhæver en struktur, en stor del er flydende. Men at overholde en bestemt rækkefølge, hvor elementerne placeres i en kildefil, kan forbedre kodelæsbarheden betydeligt. Der er flere populære stilguider at hente inspiration fra, som en af Google og en anden af Spring.
Lad os se, hvordan en typisk ordning af elementer i en kildefil skal se ud:
- Pakkeerklæring
- Importer udsagn
- Al statisk import
- Al ikke-statisk import
- Præcis en topklasse
- Klassevariabler
- Instansvariabler
- Konstruktører
- Metoder
Bortset fra ovenstående, metoder kan grupperes ud fra deres funktionalitet eller omfang. Der er ingen god konvention, og ideen burde være besluttede en gang og fulgte derefter konsekvent.
Lad os se en velformet kildefil:
# /src/main/java/com/baeldung/application/entity/Customer.java pakke com.baeldung.application.entity; importere java.util.Date; offentlig klasse kunde {privat streng kundenavn; privat Date joiningDate; offentlig kunde (streng kundenavn) {this.customerName = kundenavn; this.joiningDate = ny dato (); } offentlig streng getCustomerName () {returner this.customerName; } offentlig dato getJoiningDate () {returner this.joiningDate; }}
5.4. Hvide rum
Vi ved alle, at det er lettere at læse og forstå korte afsnit sammenlignet med en stor tekstblok. Det er ikke meget anderledes, når det kommer til at læse kode også. Velplacerede og ensartede mellemrum og tomme linjer kan forbedre læsbarheden af koden.
Ideen her er at introducere logiske grupperinger i koden, som kan hjælpe med at organisere tankeprocesser, mens du prøver at læse den igennem. Der er ingen enkelt regel at vedtage her, men et generelt sæt retningslinjer og en iboende hensigt om at holde læsbarheden i centrum af den:
- To blanke linjer inden statiske blokke, felter, konstruktører og indre klasser startes
- Én tom linje efter en metodesignatur, der er multiline
- Et enkelt mellemrum, der adskiller reserverede nøgleord, som hvis, for, fangst fra åbne parenteser
- Et enkelt mellemrum, der adskiller reserverede søgeord som andet, fanges fra en afsluttende parentes
Listen her er ikke udtømmende, men bør give os et indflydelse at gå mod.
5.5. Indrykning
Selvom det er ganske trivielt, vil næsten enhver udvikler garantere, at en velindrykket kode er meget lettere at læse og forstå. Der er ingen enkelt konvention til kodeindrykk i Java. Nøglen her er at enten vedtage en populær konvention eller definere en privat og derefter følge den konsekvent på tværs af organisationen.
Lad os se nogle af de vigtige indrykningskriterier:
- En typisk bedste praksis er at bruge fire mellemrum, en indrykningsenhed. Bemærk, at nogle retningslinjer foreslår en fane i stedet for mellemrum. Selvom der ikke er nogen absolut bedste praksis her, forbliver nøglen konsistens!
- Normalt skal der være en hætte over linjelængden, men denne kan indstilles højere end traditionelle 80 på grund af større skærme, som udviklere bruger i dag.
- Endelig, da mange udtryk ikke passer ind i en enkelt linje, skal vi bryde dem konsekvent:
- Break-metode kald efter et komma
- Bryde udtryk for en operatør
- Indrykkede linier for bedre læsbarhed (vi her i Baeldung foretrækker to mellemrum)
Lad os se et eksempel:
Liste med customerIds = customer.stream () .map (customer -> customer.getCustomerId ()) .collect (Collectors.toCollection (ArrayList :: new));
5.6. Metodeparametre
Parametre er vigtige for, at metoder fungerer efter specifikation. Men, en lang liste med parametre kan gøre det vanskeligt for nogen at læse og forstå koden. Så hvor skal vi trække grænsen? Lad os forstå de bedste fremgangsmåder, der kan hjælpe os:
- Prøv at begrænse antallet af parametre, som en metode accepterer, tre parametre kan være et godt valg
- Overvej at omlægge metoden, hvis den har brug for mere end anbefalede parametre, typisk angiver en lang parameterliste også, at metoden kan udføre flere ting
- Vi kan overveje at samle parametre i brugerdefinerede typer, men vi skal være forsigtige med ikke at dumpe ikke-relaterede parametre til en enkelt type
- Endelig, mens vi skal bruge dette forslag til at bedømme læsbarheden af koden, må vi ikke være pedantiske om det
Lad os se et eksempel på dette:
public boolean setCustomerAddress (String firstName, String lastName, String streetAddress, String city, String zipCode, String state, String country, String phoneNumber) {} // Dette kan omformuleres som nedenfor for at øge læsbarheden public boolean setCustomerAddress (Adresse adresse) {}
5.7. Hardcoding
Hardcoding-værdier i kode kan ofte føre til flere bivirkninger. For eksempel, det kan føre til dobbeltarbejde, hvilket gør ændringer vanskeligere. Det kan ofte føre til uønsket adfærd, hvis værdierne skal være dynamiske. I de fleste tilfælde kan hardkodede værdier omformuleres på en af følgende måder:
- Overvej at erstatte med konstanter eller enums defineret i Java
- Ellers skal du erstatte med konstanter defineret på klasseniveau eller i en separat klassefil
- Hvis det er muligt, skal du erstatte det med værdier, der kan vælges fra konfiguration eller miljø
Lad os se et eksempel:
private int storeClosureDay = 7; // Dette kan refaktoriseres for at bruge en konstant fra Java private int storeClosureDay = DayOfWeek.SUNDAY.getValue ()
Igen er der ingen streng retningslinje omkring dette at overholde. Men vi skal være opmærksomme på, at nogle bliver nødt til at læse og vedligeholde denne kode senere. Vi bør vælge en konvention, der passer os, og være konsekvent omkring den.
5.8. Kode kommentarer
Kodekommentarer kan være gavnligt under læsning af kode for at forstå de ikke-trivielle aspekter. Samtidig skal man være opmærksom på ikke medtage åbenlyse ting i kommentarerne. Dette kan sprænge kommentarer, hvilket gør det vanskeligt at læse de relevante dele.
Java tillader to typer kommentarer: Implementeringskommentarer og dokumentationskommentarer. De har også forskellige formål og forskellige formater. Lad os forstå dem bedre:
- Dokumentation / JavaDoc-kommentarer
- Publikum her er brugerne af kodebasen
- Detaljerne her er typisk implementeringsfrie og fokuserer mere på specifikationen
- Typisk nyttigt uafhængigt af kodebasen
- Implementering / Bloker kommentarer
- Publikum her er udviklerne, der arbejder på kodebasen
- Detaljerne her er implementeringsspecifikke
- Typisk nyttigt sammen med codebase
Så hvordan skal vi bruge dem optimalt, så de er nyttige og kontekstuelle?
- Kommentarer skal kun supplere en kode, hvis vi ikke er i stand til at forstå koden uden kommentarer, er vi måske nødt til at omlægge den
- Vi bør sjældent bruge blokkommentarer, muligvis til at beskrive ikke-trivielle designbeslutninger
- Vi skal bruge JavaDoc-kommentarer til de fleste af vores klasser, grænseflader, offentlige og beskyttede metoder
- Alle kommentarer skal være velformede med en korrekt indrykning for læsbarhed
Lad os se et eksempel på meningsfuld dokumentationskommentar:
/ ** * Denne metode er beregnet til at tilføje en ny adresse til kunden. * Bemærk dog, at det kun tillader en enkelt adresse pr. Postnummer *. Derfor vil dette tilsidesætte enhver tidligere adresse med * samme postnummer. * * @param-adresse en adresse, der skal tilføjes til en eksisterende kunde * / / * * Denne metode bruger den tilpassede implementering af lig med * -metoden for at undgå duplikering af en adresse med samme postnummer. * / public addCustomerAddress (Adresse-adresse) {}
5.9. Logning
Enhver, der nogensinde har lagt hænderne på produktionskoden til debugging, har længes efter flere logfiler på et eller andet tidspunkt. Det vigtigheden af logfiler kan ikke overbelastes i udviklingen generelt og vedligeholdelsen i særdeleshed.
Der er mange biblioteker og rammer i Java til logning, herunder SLF4J, Logback. Mens de gør logning temmelig triviel i en kodebase, skal man være opmærksom på at logge bedste praksis. En ellers udført skovhugst kan vise sig at være et vedligeholdelsesmareridt i stedet for nogen hjælp. Lad os gennemgå nogle af disse bedste fremgangsmåder:
- Undgå overdreven logning, tænk over, hvilke oplysninger der kan være til hjælp ved fejlfinding
- Vælg logniveauer klogt, vi vil muligvis aktivere logniveauer selektivt i produktionen
- Vær meget klar og beskrivende med kontekstuelle data i logmeddelelsen
- Brug eksterne værktøjer til sporing, sammenlægning, filtrering af logbeskeder til hurtigere analyse
Lad os se et eksempel på beskrivende logning med det rigtige niveau:
logger.info (String.format ("En ny kunde er oprettet med kunde-id:% s", id));
6. Er det alt det?
Mens det forrige afsnit fremhæver adskillige kodeformateringskonventioner, er det ikke de eneste, vi bør kende og bryr os om. En læsbar og vedligeholdelig kode kan drage fordel af et stort antal yderligere bedste praksis, der er blevet akkumuleret over tid.
Vi har muligvis stødt på dem som sjove akronymer over tid. De i det væsentlige fange læringen som en enkelt eller et sæt principper, der kan hjælpe os med at skrive bedre kode. Bemærk dog, at vi ikke skal følge dem alle, bare fordi de findes. Det meste af tiden er den fordel, de giver, proportional med størrelsen og kompleksiteten af kodebasen. Vi skal få adgang til vores kodebase, inden vi vedtager ethvert princip. Endnu vigtigere skal vi forblive i overensstemmelse med dem.
6.1. SOLID
SOLID er et mnemonisk akronym, der trækker fra de fem principper, som det fremgår for at skrive forståelig og vedligeholdelig software:
- Princip for et enkelt ansvar: Hver interface, klasse eller metode, vi definerer, skal have et klart defineret mål. I det væsentlige skal det ideelt set gøre en ting og gøre det godt. Dette fører effektivt til mindre metoder og klasser, som også kan testes.
- Åben-lukket princip: Koden, som vi skriver, skal ideelt set være åben for udvidelse, men lukket for ændringer. Hvad dette effektivt betyder er, at en klasse skal skrives på en måde, så der ikke skal være behov for at ændre den. Det skal dog muliggøre ændringer gennem arv eller sammensætning.
- Princip for udskiftning af Liskov: Hvad dette princip siger er, at hver underklasse eller afledt klasse skal erstatte deres forælder eller basisklasse. Dette hjælper med at reducere kobling i codebase og dermed forbedre genanvendelighed på tværs.
- Princip for adskillelse af grænseflade: Implementering af en grænseflade er en måde at give vores klasse en bestemt opførsel. Imidlertid, en klasse behøver ikke at implementere metoder, som den ikke kræver. Hvad dette kræver, at vi gør, er at definere mindre, mere fokuserede grænseflader.
- Princip for afhængighedsinversion: I henhold til dette princip, klasser bør kun afhænge af abstraktioner og ikke af deres konkrete implementeringer. Dette betyder effektivt, at en klasse ikke skal være ansvarlig for at skabe forekomster for deres afhængighed. Snarere bør sådanne afhængigheder injiceres i klassen.
6.2. TØR & KYS
DRY står for "Don's Repeat Yourself". Dette princip siger det et stykke kode bør ikke gentages på tværs af softwaren. Begrundelsen bag dette princip er at reducere dobbeltarbejde og øge genanvendelighed. Vær dog opmærksom på, at vi skal være forsigtige med at vedtage dette temmelig for bogstaveligt. Noget duplikering kan faktisk forbedre kodelæsbarhed og vedligeholdelse.
KISS står for "Keep It Simple, Stupid". Dette princip siger det vi skal prøve at holde koden så enkel som muligt. Dette gør det let at forstå og vedligeholde over tid. Ved at følge nogle af de tidligere nævnte principper, hvis vi holder vores klasser og metoder fokuseret og små, vil dette føre til enklere kode.
6.3. TDD
TDD står for “Test Driven Development”. Dette er en programmeringspraksis, der kun beder os om at skrive en hvilken som helst kode, hvis en automatiseret test mislykkes. Derfor må vi start med designudviklingen af automatiserede tests. I Java er der flere rammer til at skrive automatiserede enhedstest som JUnit og TestNG.
Fordelene ved sådan praksis er enorme. Dette fører til software, der altid fungerer som forventet. Da vi altid starter med test, tilføjer vi trinvist arbejdskode i små bidder. Vi tilføjer kun kode, hvis den nye eller nogen af de gamle tests mislykkes. Hvilket betyder, at det også fører til genanvendelighed.
7. Værktøjer til hjælp
At skrive ren kode er ikke kun et spørgsmål om principper og praksis, men det er en personlig vane. Vi har tendens til at vokse som bedre udviklere, når vi lærer og tilpasser os. For at opretholde konsistens på tværs af et stort hold skal vi dog også øve noget håndhævelse. Kode anmeldelser har altid været et godt værktøj til at opretholde konsistens og hjælpe udviklerne med at vokse gennem konstruktiv feedback.
Vi behøver dog ikke nødvendigvis at validere alle disse principper og bedste fremgangsmåder manuelt under kodevurderinger. Freddy Guime fra Java OffHeap taler om værdien af at automatisere nogle af kvalitetskontrollerne for at ende med en bestemt tærskel med kodekvaliteten hele tiden.
Der er flere tilgængelige værktøjer i Java-økosystemet, der i det mindste fjerner nogle af disse ansvarsområder fra kodevurderere. Lad os se, hvad nogle af disse værktøjer er:
- Kodeformater: De fleste af de populære Java-kodeditorer, inklusive Eclipse og IntelliJ, giver mulighed for automatisk kodeformatering. Vi kan bruge standardformateringsreglerne, tilpasse dem eller erstatte dem med tilpassede formateringsregler. Dette tager sig af mange strukturelle kodekonventioner.
- Statiske analyseværktøjer: Der er flere statiske kodeanalyseværktøjer til Java, herunder SonarQube, Checkstyle, PMD og SpotBugs. De har et rigt sæt regler, der kan bruges som de er eller tilpasses til et specifikt projekt. De er gode til at opdage en masse kodelugt som krænkelser af navngivningskonventioner og ressourceudslip.
8. Konklusion
I denne vejledning har vi gennemgået vigtigheden af rene kodningsprincipper og egenskaber, som ren kode udviser. Vi så, hvordan man vedtager nogle af disse principper i praksis, som udvikler sig i Java. Vi diskuterede også andre bedste fremgangsmåder, der hjælper med at holde koden læsbar og vedligeholdelig over tid. Endelig diskuterede vi nogle af de tilgængelige værktøjer til at hjælpe os i denne bestræbelse.
For at opsummere er det vigtigt at bemærke, at alle disse principper og praksis er der for at gøre vores kode renere. Dette er et mere subjektivt udtryk og skal derfor vurderes sammenhængende.
Mens der er adskillige sæt regler til rådighed til at vedtage, skal vi være opmærksomme på vores modenhed, kultur og krav. Vi bliver muligvis nødt til at tilpasse eller for den sags skyld udtænke et nyt sæt regler helt. Men uanset hvad der er tilfældet, er det vigtigt at være konsekvent i hele organisationen for at høste fordelene.