Schone codering in Java

1. Overzicht

In deze tutorial gaan we door met schone coderingsprincipes. We zullen ook begrijpen waarom schone code belangrijk is en hoe u dat in Java kunt bereiken. Verder zullen we kijken of er tools beschikbaar zijn om ons te helpen.

2. Wat is schone code?

Laten we dus, voordat we ingaan op de details van schone code, begrijpen wat we bedoelen met schone code. Eerlijk gezegd kan hier geen goed antwoord op zijn. Bij de programmering reiken sommige zorgen over en resulteren dus in algemene principes. Maar dan, elke programmeertaal en elk paradigma presenteert zijn eigen set van nuances, wat ons verplicht om passende praktijken toe te passen.

Breed, schone code kan worden samengevat als een code die elke ontwikkelaar gemakkelijk kan lezen en wijzigen. Hoewel dit klinkt als een oversimplificatie van het concept, zullen we later in de tutorial zien hoe dit zich ontwikkelt. Overal waar we horen over schone code, komen we misschien een verwijzing naar Martin Fowler tegen. Hier is hoe hij schone code op een van de plaatsen beschrijft:

Elke dwaas kan code schrijven die een computer kan begrijpen. Goede programmeurs schrijven code die mensen kunnen begrijpen.

3. Waarom zouden we ons om schone code moeten bekommeren?

Het schrijven van schone code is zowel een kwestie van persoonlijke gewoonte als van vaardigheid. Als ontwikkelaar groeien we in de loop van de tijd door ervaring en kennis. Maar we moeten ons afvragen waarom we toch zouden moeten investeren in het ontwikkelen van schone code? We snappen dat anderen het waarschijnlijk gemakkelijker zullen vinden om onze code te lezen, maar is dat voldoende stimulans? Dat zoeken we uit!

Schone coderingsprincipes helpen ons veel gewenste doelen te bereiken met betrekking tot de software die we willen produceren. Laten we ze doornemen om het beter te begrijpen:

  • Onderhoudbare codebase: Alle software die we ontwikkelen, heeft een productieve levensduur en vereist gedurende deze periode wijzigingen en algemeen onderhoud. Schone code kan helpen bij het ontwikkelen van software die gemakkelijk te wijzigen en te onderhouden is na verloop van tijd.
  • Gemakkelijkere probleemoplossing: Software kan onbedoeld gedrag vertonen als gevolg van verschillende interne of externe factoren. Het kan vaak een snelle doorlooptijd vereisen in termen van oplossingen en beschikbaarheid. Software ontwikkeld met schone coderingsprincipes is gemakkelijker op te lossen voor problemen.
  • Snellere introductie: Software zal tijdens zijn levensduur veel ontwikkelaars zien maken, updaten en onderhouden, waarbij ontwikkelaars op verschillende momenten in de tijd meedoen. Dit vereist een snellere introductie om de productiviteit hoog te houden, en schone code helpt dit doel te bereiken.

4. Kenmerken van Clean Code

Codebases die zijn geschreven met zuivere coderingsprincipes vertonen verschillende kenmerken die hen onderscheiden. Laten we enkele van deze kenmerken doornemen:

  • Gefocust: Een stuk van code moet worden geschreven om een ​​specifiek probleem op te lossen. Het mag niets doen dat strikt niets te maken heeft met het oplossen van het gegeven probleem. Dit is van toepassing op alle abstractieniveaus in de codebase, zoals methode, klasse, pakket of module.
  • Gemakkelijk: Dit is verreweg het belangrijkste en vaak genegeerde kenmerk van schone code. De software ontwerp en uitvoering moeten zo eenvoudig mogelijk zijn, wat ons kan helpen de gewenste resultaten te bereiken. Toenemende complexiteit in een codebase maakt ze foutgevoelig en moeilijk te lezen en te onderhouden.
  • Testbaar: Schone code, hoewel eenvoudig, moet het probleem oplossen. Het moet zijn intuïtief en gemakkelijk om de codebase te testen, bij voorkeur op een geautomatiseerde manier. Dit helpt bij het vaststellen van het basisgedrag van de codebase en maakt het gemakkelijker om deze te wijzigen zonder iets te breken.

Dit zijn wat ons helpt de doelen te bereiken die in de vorige sectie zijn besproken. Het is gunstig om te beginnen met ontwikkelen met deze kenmerken in gedachten in vergelijking met refactor later. Dit leidt tot lagere totale eigendomskosten voor de levenscyclus van software.

5. Schone codering in Java

Nu we genoeg achtergrondinformatie hebben doorlopen, laten we eens kijken hoe we schone coderingsprincipes in Java kunnen opnemen. Java biedt veel best practices die ons kunnen helpen schone code te schrijven. We categoriseren ze in verschillende buckets en begrijpen hoe we schone code kunnen schrijven met codevoorbeelden.

5.1. Projectstructuur

Hoewel Java geen enkele projectstructuur afdwingt, het is altijd handig om een ​​consistent patroon te volgen om onze bronbestanden, tests, configuraties, gegevens en andere code-artefacten te ordenen. Maven, een populaire build-tool voor Java, schrijft een bepaalde projectstructuur voor. Hoewel we Maven misschien niet gebruiken, is het altijd fijn om vast te houden aan een conventie.

Laten we eens kijken naar enkele van de mappen waarvan Maven suggereert dat we ze maken:

  • src / main / java: Voor bronbestanden
  • src / main / resources: Voor bronbestanden, zoals eigenschappen
  • src / test / java: Voor testbronbestanden
  • src / test / resources: Voor testbronbestanden, zoals eigenschappen

Vergelijkbaar met dit zijn er andere populaire projectstructuren zoals Bazel suggereerde voor Java, en we zouden er een moeten kiezen afhankelijk van onze behoeften en publiek.

5.2. Naamgeving

Als vervolg op naamgevingsconventies kunnen een lange weg helpen om onze code leesbaar en dus onderhoudbaar te maken. Rod Johnson, de maker van Spring, benadrukt het belang van naamgevingsconventies in Spring:

"... als je weet wat iets doet, heb je een goede kans om de naam van de Spring-klasse of interface ervoor te raden ..."

Java schrijft een reeks regels voor waaraan u zich moet houden als het gaat om het benoemen van iets in Java. Een goedgevormde naam helpt niet alleen bij het lezen van de code, maar zegt ook veel over de bedoeling van de code. Laten we een paar voorbeelden nemen:

  • Klassen: Klasse in termen van objectgeoriënteerde concepten is een blauwdruk voor objecten die vaak objecten uit de echte wereld vertegenwoordigen. Daarom is het zinvol om zelfstandige naamwoorden te gebruiken om klassen een naam te geven die ze voldoende beschrijft:
openbare klasse Klant {}
  • Variabelen: Variabelen in Java leggen de status vast van het object dat is gemaakt op basis van een klasse. De naam van de variabele moet de bedoeling van de variabele duidelijk beschrijven:
openbare klasse Customer {private String customerName; }
  • Methoden: Methoden in Java maken altijd deel uit van klassen en vertegenwoordigen daarom over het algemeen een actie op de toestand van het object dat vanuit de klasse is gemaakt. Het is daarom handig om methoden te noemen die werkwoorden gebruiken:
openbare klasse Customer {private String customerName; public String getCustomerName () {retourneer this.customerName; }}

Hoewel we alleen hebben besproken hoe u een identifier in Java een naam geeft, moet u er rekening mee houden dat er aanvullende best practices zijn, zoals camel casing, die we in acht moeten nemen voor de leesbaarheid. Er kunnen ook meer conventies zijn met betrekking tot naamgeving van interfaces, enums, constanten.

5.3. Bronbestandsstructuur

Een bronbestand kan verschillende elementen bevatten. Terwijl Java compiler dwingt enige structuur af, een groot deel is vloeiend. Maar het naleven van een specifieke volgorde waarin elementen in een bronbestand worden geplaatst, kan de leesbaarheid van de code aanzienlijk verbeteren. Er zijn meerdere populaire stijlgidsen om inspiratie uit te putten, zoals een van Google en een andere van Spring.

Laten we eens kijken hoe een typische volgorde van elementen in een bronbestand eruit zou moeten zien:

  • Pakketverklaring
  • Afschriften importeren
    • Alle statische invoer
    • Alle niet-statische invoer
  • Precies een klasse op het hoogste niveau
    • Klassevariabelen
    • Instantievariabelen
    • Constructeurs
    • Methoden

Afgezien van het bovenstaande, methoden kunnen worden gegroepeerd op basis van hun functionaliteit of bereik. Er is niet één goede conventie, en het idee zou dat ook moeten zijn eenmaal besloten en daarna consequent gevolgd.

Laten we eens kijken naar een goed gevormd bronbestand:

# /src/main/java/com/baeldung/application/entity/Customer.java pakket com.baeldung.application.entity; importeer java.util.Date; openbare klasse Customer {private String customerName; privé Datum joinDate; openbare klant (string klantnaam) {this.customerName = klantnaam; this.joiningDate = nieuwe datum (); } public String getCustomerName () {retourneer this.customerName; } public Date getJoiningDate () {retourneer this.joiningDate; }}

5.4. Witruimten

We weten allemaal dat het gemakkelijker is om korte alinea's te lezen en te begrijpen in vergelijking met een groot blok tekst. Het is ook niet heel anders als het gaat om het lezen van code. Goed geplaatste en consistente witruimten en lege regels kunnen de leesbaarheid van de code verbeteren.

Het idee hier is om logische groeperingen in de code te introduceren die kunnen helpen bij het organiseren van denkprocessen terwijl je deze probeert door te lezen. Er is hier niet één enkele regel die moet worden aangenomen, maar een algemene reeks richtlijnen en een inherente bedoeling om de leesbaarheid centraal te houden:

  • Twee lege regels voordat statische blokken, velden, constructeurs en innerlijke klassen worden gestart
  • Een lege regel na een methodehandtekening die uit meerdere regels bestaat
  • Een enkele spatie tussen gereserveerde trefwoorden, zoals if, for, catch van een open haakje
  • Een enkele spatie die gereserveerde trefwoorden scheidt, zoals anders, vangen op tussen haakjes sluiten

De lijst hier is niet uitputtend, maar zou ons richting moeten geven.

5.5. Inspringing

Hoewel vrij triviaal, zou bijna elke ontwikkelaar daarvoor instaan een goed ingesprongen code is veel gemakkelijker te lezen en te begrijpen. Er is geen enkele conventie voor code-inspringing in Java. De sleutel hier is om een ​​populaire conventie aan te nemen of een privéconventie te definiëren en deze vervolgens consequent door de hele organisatie te volgen.

Laten we eens kijken naar enkele van de belangrijke inspringcriteria:

  • Een typische best practice is om vier spaties te gebruiken, een eenheid van inspringen. Houd er rekening mee dat sommige richtlijnen een tab suggereren in plaats van spaties. Hoewel er hier geen absolute best practice is, blijft de sleutel consistentie!
  • Normaal gesproken zou er een limiet moeten zijn voor de lijnlengte, maar deze kan hoger worden ingesteld dan traditionele 80 vanwege grotere schermen die ontwikkelaars tegenwoordig gebruiken.
  • Ten slotte, aangezien veel uitdrukkingen niet op één regel passen, moeten we ze consequent afbreken:
    • Break-methode roept na een komma aan
    • Breek uitdrukkingen af ​​vóór een operator
    • Omwikkelde regels inspringen voor betere leesbaarheid (wij hier bij Baeldung geven de voorkeur aan twee spaties)

Laten we een voorbeeld bekijken:

Lijst customerIds = customer.stream () .map (klant -> customer.getCustomerId ()) .collect (Collectors.toCollection (ArrayList :: nieuw));

5.6. Methode Parameters

Parameters zijn essentieel om methoden volgens de specificatie te laten werken. Maar, een lange lijst met parameters kan het voor iemand moeilijk maken om de code te lezen en te begrijpen. Dus, waar moeten we de grens trekken? Laten we de best practices begrijpen die ons kunnen helpen:

  • Probeer het aantal parameters dat een methode accepteert te beperken, drie parameters kunnen een goede keuze zijn
  • Overweeg om de methode te herstructureren als deze meer dan aanbevolen parameters nodig heeft, meestal geeft een lange parameterlijst ook aan dat de methode mogelijk meerdere dingen doet
  • We kunnen overwegen om parameters in aangepaste typen te bundelen, maar we moeten oppassen dat we geen niet-gerelateerde parameters in een enkel type dumpen
  • Ten slotte, hoewel we deze suggestie moeten gebruiken om de leesbaarheid van de code te beoordelen, moeten we er niet pedant over zijn

Laten we een voorbeeld hiervan bekijken:

public boolean setCustomerAddress (String firstName, String lastName, String streetAddress, String city, String zipCode, String state, String country, String phoneNumber) {} // Dit kan worden aangepast zoals hieronder om de leesbaarheid te vergroten public boolean setCustomerAddress (adresadres) {}

5.7. Hardcodering

Hardcoderingswaarden in code kunnen vaak tot meerdere bijwerkingen leiden. Bijvoorbeeld, het kan leiden tot duplicatie, waardoor verandering moeilijker wordt. Het kan vaak leiden tot ongewenst gedrag als de waarden dynamisch moeten zijn. In de meeste gevallen kunnen hardcoded waarden op een van de volgende manieren worden geherstructureerd:

  • Overweeg om te vervangen door constanten of enums die zijn gedefinieerd in Java
  • Of vervang door constanten die zijn gedefinieerd op klassenniveau of in een apart klassebestand
  • Vervang indien mogelijk door waarden die uit de configuratie of omgeving kunnen worden gehaald

Laten we een voorbeeld bekijken:

private int storeClosureDay = 7; // Dit kan worden geherstructureerd om een ​​constante van Java te gebruiken private int storeClosureDay = DayOfWeek.SUNDAY.getValue ()

Nogmaals, er is geen strikte richtlijn om je aan te houden. Maar we moeten er rekening mee houden dat sommigen deze code later zullen moeten lezen en onderhouden. We zouden een conventie moeten kiezen die bij ons past en daar consistent in zijn.

5.8. Code opmerkingen

Code opmerkingen kunnen zijn nuttig bij het lezen van code om de niet-triviale aspecten te begrijpen. Tegelijkertijd moet er op worden gelet neem geen voor de hand liggende dingen op in de commentaren. Dit kan reacties opzwellen, waardoor het moeilijk wordt om de relevante delen te lezen.

Java staat twee soorten opmerkingen toe: implementatieopmerkingen en documentatieopmerkingen. Ze hebben ook verschillende doeleinden en verschillende formaten. Laten we ze beter begrijpen:

  • Documentatie / JavaDoc-opmerkingen
    • Het publiek hier zijn de gebruikers van de codebase
    • De details hier zijn meestal implementatievrij, waarbij de nadruk meer ligt op de specificatie
    • Meestal bruikbaar onafhankelijk van de codebase
  • Implementatie / blokkeer opmerkingen
    • Het publiek hier zijn de ontwikkelaars die aan de codebase werken
    • De details hier zijn implementatiespecifiek
    • Meestal handig in combinatie met de codebase

Dus, hoe moeten we ze optimaal gebruiken, zodat ze nuttig en contextueel zijn?

  • Opmerkingen zouden alleen een code moeten aanvullen, als we de code niet zonder opmerkingen kunnen begrijpen, moeten we deze misschien herstructureren
  • We zouden zelden blokcommentaar moeten gebruiken, mogelijk om niet-triviale ontwerpbeslissingen te beschrijven
  • We zouden JavaDoc-opmerkingen moeten gebruiken voor de meeste van onze klassen, interfaces, openbare en beschermde methoden
  • Alle opmerkingen moeten goed worden gevormd met een goede inspringing voor leesbaarheid

Laten we eens kijken naar een voorbeeld van zinvolle documentatiecommentaar:

/ ** * Deze methode is bedoeld om een ​​nieuw adres voor de klant toe te voegen. * Houd er echter rekening mee dat het slechts één adres per postcode * toestaat. Dit zal dus elk eerder adres met dezelfde postcode overschrijven. * * @param adres een adres dat moet worden toegevoegd voor een bestaande klant * / / * * Deze methode maakt gebruik van de aangepaste implementatie van de equals * -methode om duplicatie van een adres met dezelfde postcode te voorkomen. * / public addCustomerAddress (adresadres) {}

5.9. Logboekregistratie

Iedereen die ooit productiecode voor foutopsporing in handen heeft gehad, heeft op een bepaald moment naar meer logboeken verlangd. De Het belang van boomstammen kan niet genoeg worden benadrukt bij ontwikkeling in het algemeen en onderhoud in het bijzonder.

Er zijn veel bibliotheken en frameworks in Java voor logboekregistratie, waaronder SLF4J, Logback. Hoewel ze het loggen in een codebase vrij triviaal maken, moet er aandacht worden besteed aan de beste praktijken voor loggen. Een anders uitgevoerde houtkap kan een nachtmerrie voor onderhoud blijken te zijn in plaats van enige hulp. Laten we enkele van deze praktische tips doornemen:

  • Vermijd overmatig loggen, bedenk welke informatie kan helpen bij het oplossen van problemen
  • Kies logboekniveaus verstandig, we willen misschien logboekniveaus selectief inschakelen voor productie
  • Wees heel duidelijk en beschrijvend met contextuele gegevens in het logbericht
  • Gebruik externe tools voor tracering, aggregatie en filtering van logboekberichten voor snellere analyses

Laten we eens kijken naar een voorbeeld van beschrijvende logboekregistratie met het juiste niveau:

logger.info (String.format ("Er is een nieuwe klant aangemaakt met klant-id:% s", id));

6. Is dat alles?

Hoewel in de vorige sectie verschillende conventies voor code-opmaak worden genoemd, zijn dit niet de enige die we zouden moeten kennen en waar we om moeten geven. Een leesbare en onderhoudbare code kan profiteren van een groot aantal aanvullende best practices die in de loop van de tijd zijn verzameld.

We zijn ze in de loop van de tijd misschien als grappige afkortingen tegengekomen. Ze in wezen de lessen vastleggen als een enkele of een reeks principes die ons kunnen helpen betere code te schrijven. Houd er echter rekening mee dat we ze niet allemaal moeten volgen alleen omdat ze bestaan. Meestal is het voordeel dat ze bieden evenredig aan de grootte en complexiteit van de codebase. We moeten toegang hebben tot onze codebase voordat we een principe kunnen toepassen. Wat nog belangrijker is, we moeten consistent blijven met hen.

6.1. SOLIDE

SOLID is een mnemonisch acroniem dat put uit de vijf principes die het uiteenzet voor het schrijven van begrijpelijke en onderhoudbare software:

  • Eén verantwoordelijkheidsbeginsel: Elke interface, klasse of methode die we definiëren, moet een duidelijk gedefinieerd doel hebben. In wezen zou het idealiter één ding moeten doen en dat goed doen. Dit leidt effectief tot kleinere methoden en klassen die ook toetsbaar zijn.
  • Open-gesloten principe: De code die we schrijven zou idealiter open voor uitbreiding maar gesloten voor wijziging. Wat dit in feite betekent, is dat een klasse zo moet worden geschreven dat deze niet hoeft te worden gewijzigd. Het moet echter veranderingen door overerving of samenstelling mogelijk maken.
  • Liskov-vervangingsprincipe: Wat dit principe stelt is dat elke subklasse of afgeleide klasse zou substitueerbaar moeten zijn voor hun bovenliggende of basisklasse. Dit helpt bij het verminderen van de koppeling in de codebase en verbetert daarmee de herbruikbaarheid over.
  • Interface-segregatieprincipe: Het implementeren van een interface is een manier om specifiek gedrag aan onze klas te geven. Echter, een klasse hoeft geen methoden te hoeven implementeren die ze niet nodig heeft. Dit vereist dat we kleinere, meer gerichte interfaces definiëren.
  • Afhankelijkheidsinversieprincipe: Volgens dit principe, klassen zouden alleen afhankelijk moeten zijn van abstracties en niet van hun concrete implementaties. Dit betekent in feite dat een klasse niet verantwoordelijk mag zijn voor het maken van instanties voor hun afhankelijkheden. Dergelijke afhankelijkheden zouden eerder in de klasse moeten worden geïnjecteerd.

6.2. DROOG & KUS

DRY staat voor "Don's Repeat Yourself". Dit principe stelt dat een stukje code mag niet worden herhaald in de software. De grondgedachte achter dit principe is om duplicatie te verminderen en herbruikbaarheid te vergroten. Houd er echter rekening mee dat we voorzichtig moeten zijn door dit nogal te letterlijk over te nemen. Enige duplicatie kan de leesbaarheid en onderhoudbaarheid van de code zelfs verbeteren.

KISS staat voor "Keep It Simple, Stupid". Dit principe stelt dat we moeten proberen de code zo eenvoudig mogelijk te houden. Dit maakt het gemakkelijk te begrijpen en in de loop van de tijd te onderhouden. Als we enkele van de eerder genoemde principes volgen, zal dit leiden tot eenvoudigere code als we onze klassen en methoden gefocust en klein houden.

6.3. TDD

TDD staat voor "Test Driven Development". Dit is een programmeerpraktijk die ons vraagt ​​om alleen code te schrijven als een geautomatiseerde test mislukt. Daarom moeten we begin met de ontwerpontwikkeling van geautomatiseerde tests. In Java zijn er verschillende frameworks om geautomatiseerde unit-tests te schrijven, zoals JUnit en TestNG.

De voordelen van een dergelijke praktijk zijn enorm. Dit leidt tot software die altijd werkt zoals verwacht. Omdat we altijd beginnen met testen, voegen we stapsgewijs werkende code in kleine stukjes toe. We voegen ook alleen code toe als de nieuwe of een van de oude tests mislukt. Wat betekent dat het ook leidt tot herbruikbaarheid.

7. Hulpmiddelen voor hulp

Het schrijven van schone code is niet alleen een kwestie van principes en praktijken, maar het is ook een persoonlijke gewoonte. We hebben de neiging om te groeien als betere ontwikkelaars naarmate we leren en ons aanpassen. Om de consistentie binnen een groot team te behouden, moeten we echter ook enige handhaving toepassen. Code recensies zijn altijd een geweldig hulpmiddel geweest om de consistentie te behouden en de ontwikkelaars helpen groeien door constructieve feedback.

We hoeven echter niet per se al deze principes en best practices handmatig te valideren tijdens codebeoordelingen. Freddy Guime van Java OffHeap vertelt over de waarde van het automatiseren van een aantal kwaliteitscontroles om altijd een bepaalde drempel te bereiken met de codekwaliteit.

Er zijn verschillende tools beschikbaar in het Java-ecosysteem, die ten minste een deel van deze verantwoordelijkheden wegnemen van code reviewers. Laten we eens kijken wat enkele van deze tools zijn:

  • Code-opmaakprogramma's: De meeste populaire Java-code-editors, waaronder Eclipse en IntelliJ, maken automatische code-opmaak mogelijk. We kunnen de standaard opmaakregels gebruiken, deze aanpassen of vervangen door aangepaste opmaakregels. Dit zorgt voor veel structurele codeconventies.
  • Statische analysehulpmiddelen: er zijn verschillende analysehulpmiddelen voor statische code voor Java, waaronder SonarQube, Checkstyle, PMD en SpotBugs. Ze hebben een uitgebreide reeks regels die kunnen worden gebruikt zoals ze zijn of die kunnen worden aangepast voor een specifiek project. Ze zijn geweldig in het detecteren van veel codegeuren, zoals schendingen van naamgevingsconventies en het weglekken van bronnen.

8. Conclusie

In deze zelfstudie hebben we het belang besproken van schone coderingsprincipes en -kenmerken die schone code vertoont. We hebben gezien hoe we enkele van deze principes in de praktijk kunnen toepassen, die zich ontwikkelen in Java. We hebben ook andere best practices besproken die helpen om de code na verloop van tijd leesbaar en onderhoudbaar te houden. Ten slotte hebben we enkele van de beschikbare tools besproken om ons hierbij te helpen.

Samenvattend is het belangrijk op te merken dat al deze principes en praktijken er zijn om onze code schoner te maken. Dit is een meer subjectieve term en moet daarom contextueel worden geëvalueerd.

Hoewel er talloze regels beschikbaar zijn om aan te nemen, moeten we ons bewust zijn van onze volwassenheid, cultuur en vereisten. Het kan zijn dat we aanpassingen moeten maken of zelfs een geheel nieuwe set regels moeten bedenken. Maar wat het ook moge zijn, het is belangrijk om consistent te blijven in de hele organisatie om de vruchten te plukken.