Ren kode forklaret - en praktisk introduktion til ren kodning for begyndere

"Enhver fjols kan skrive kode, som en computer kan forstå. Gode ​​programmører skriver kode, som mennesker kan forstå. "- Martin Fowler

At skrive ren, forståelig og vedligeholdelig kode er en færdighed, der er afgørende for enhver udvikler at mestre.

I dette indlæg vil vi se på de vigtigste principper for at forbedre kodekvaliteten, og jeg vil give dig kodeeksempler for hver af dem.

De fleste eksempler er hentet fra Robert J. Martins Clean Code . Det er en programmeringsklassiker, og jeg foreslår, at du læser hele teksten, når du har tid.

Sådan navngives variabler (og andre ting)

"Der er kun to hårde ting i datalogi: ugyldiggørelse af cache og navngivning af ting." - Phil Karlton

Der er en grund til, at vi ikke bruger hukommelsesadresser og i stedet har navne: navne er meget lettere at huske. Og vigtigere, de kan give dig flere oplysninger om variablen, så en anden kan forstå dens betydning.

Det kan tage lidt tid at finde et godt navn, men det vil spare dig og dit team endnu mere tid i fremtiden. Og jeg er sikker på, at de fleste læsere har stået over for situationen, hvor du kun besøger din kode et par måneder senere og har svært ved at forstå, hvad du gjorde før.

Sådan oprettes meningsfulde navne

Brug ikke kommentarer til at forklare, hvorfor en variabel bruges. Hvis et navn kræver en kommentar, skal du tage dig tid til at omdøbe variablen i stedet for at skrive en kommentar.

"Et navn skal fortælle dig, hvorfor det findes, hvad det gør, og hvordan det bruges. Hvis et navn kræver en kommentar, afslører navnet ikke dets hensigt." - Ren kode

Dårligt:

var d; // elapsed time in days

Jeg har set denne type kode så mange gange. Det er en almindelig misforståelse, at du skal skjule dit rod med kommentarer. Brug ikke bogstaver som x, y, a eller b som variabelnavne, medmindre der er en god grund (loop-variabler er en undtagelse fra dette).

Godt:

var elapsedTimeInDays; var daysSinceCreation; var daysSinceModification;

Disse navne er så meget bedre. De fortæller dig, hvad der måles, og måleenheden.

Undgå desinformation

Vær forsigtig med ord, der betyder noget specifikt. Henvis ikke til en gruppering af konti som accountList, medmindre dens type faktisk er en liste. Ordet har en specifik betydning, og det kan føre til falske konklusioner.

Selvom typen er en liste, er konti et enklere og bedre navn.

Dårligt:

var accountList = [];

Godt:

var accounts = []

Undgå støjord

Støjord er de ord, der ikke giver yderligere information om variablen. De er overflødige og skal fjernes.

Nogle populære støjord er:

  • (Præfikset)
  • Info
  • Data
  • Variabel
  • Objekt
  • Manager

Hvis din klasse hedder UserInfo, kan du bare fjerne info og gøre det til bruger. Brug af BookData i stedet for Book som klassenavn er bare en no-brainer, da en klasse gemmer data alligevel.

Du kan også læse Jeff Atwoods blogindlæg om navngivning af SomethingManager her.

Brug udtalt navne

Hvis du ikke kan udtale et navn, kan du ikke diskutere det uden at lyde fjollet.

Dårligt:

const yyyymmdstr = moment().format("YYYY/MM/DD"); 

Godt:

const currentDate = moment().format("YYYY/MM/DD");

Brug navne, der kan søges

Undgå at bruge magiske tal i din kode. Vælg søgbare, navngivne konstanter. Brug ikke navne på enkeltbogstaver til konstanter, da de kan vises mange steder og derfor ikke er lette at søge på.

Dårligt:

if (student.classes.length < 7) { // Do something }

Godt:

if (student.classes.length < MAX_CLASSES_PER_STUDENT) { // Do something }

Dette er meget bedre, fordi MAX_CLASSES_PER_STUDENT kan bruges mange steder i kode. Hvis vi har brug for at ændre det til 6 i fremtiden, kan vi bare ændre konstanten.

Det dårlige eksempel skaber spørgsmålstegn i læserens sind, ligesom hvad er vigtigheden af ​​7?

Du skal også gøre brug af dit sprogs konstante navngivnings- og erklæringskonventioner såsom privat statisk final i Java eller const i JavaScript.

Være konsekvent

Følg det ene ord for hver konceptregel. Brug ikke hente , hente og til den samme operation i forskellige klasser. Vælg en af ​​dem, og brug den overalt i projektet, så folk, der vedligeholder kodebasen eller klienterne i din API, nemt kan finde de metoder, de leder efter.

Sådan skriver du funktioner

Hold dem små

Funktioner skal være små, virkelig små. De skal sjældent være 20 linjer lange. Jo længere en funktion bliver, er det mere sandsynligt, at det er at gøre flere ting og have bivirkninger.

Sørg for, at de bare laver en ting

Funktioner skal gøre én ting. De skal gøre det godt. De skal kun gøre det. - Ren kode

Your functions should do only one thing. If you follow this rule, it is guaranteed that they will be small. The only thing that function does should be stated in its name.

Sometimes it is hard to look at the function and see if it is doing multiple things or not. One good way to check is to try to extract another function with a different name. If you can find it, that means it should be a different function.

This is probably the most important concept in this article, and it will take some time to get used to. But once you get the hang of it, your code will look much more mature, and it will be more easily refactorable, understandable, and testable for sure.

Encapsulate Conditionals in Functions

Refactoring the condition and putting it into a named function is a good way to make your conditionals more readable.

Here is a piece of code from a school project of mine. This code is responsible for inserting a chip on the board of the Connect4 game.

The isValidInsertion method takes care of checking the validity of the column number and allows us the focus on the logic for inserting the chip instead.

public void insertChipAt(int column) throws Exception { if (isValidInsertion(column)) { insertChip(column); boardConfiguration += column; currentPlayer = currentPlayer == Chip.RED ? Chip.YELLOW : Chip.RED; } else  if (!columnExistsAt(column)) throw new IllegalArgumentException(); else if (isColumnFull(column - 1)  }

Here is the code for isValidInsertion, if you are interested.

 private boolean isValidInsertion(int column) { boolean columnIsAvailable = column = 1 && numberOfItemsInColumn[column - 1] < NUM_ROWS; boolean gameIsOver = getWinner() != Chip.NONE; return columnIsAvailable && !gameIsOver; } 

Without the method, if condition would look like this:

if (column = 1 && numberOfItemsInColumn[column - 1] < NUM_ROWS && getWinner() != Chip.NONE)

Gross, right? I agree.

Fewer Arguments

Functions should have two or fewer arguments, the fewer the better. Avoid three or more arguments where possible.

Arguments make it harder to read and understand the function. They are even harder from a testing point of view, since they create the need to write test cases for every combination of arguments.

Do not use Flag Arguments

A flag argument is a boolean argument that is passed to a function. Two different actions are taken depending on the value of this argument.

For example, say there is a function that is responsible for booking tickets to a concert and there are 2 types of users: Premium and Regular. You can have code like this:

 public Booking book (Customer aCustomer, boolean isPremium) { if(isPremium) // logic for premium book else // logic for regular booking }

Flag arguments naturally contradict the principle of single responsibility. When you see them, you should consider dividing the function into two.

Do Not Have Side Effects

Side effects are unintended consequences of your code. They may be changing the passed parameters, in case of passing by reference, or maybe changing a global variable.

The key point is, they promised to do another thing and you need to read the code carefully to notice the side-effect. They can result in some nasty bugs.

Here is an example from the book:

public class UserValidator { private Cryptographer cryptographer; public boolean checkPassword(String userName, String password) { User user = UserGateway.findByName(userName); if (user != User.NULL) { String codedPhrase = user.getPhraseEncodedByPassword(); String phrase = cryptographer.decrypt(codedPhrase, password); if ("Valid Password".equals(phrase)) { Session.initialize(); return true; } } return false; } }

Can you see the side-effect of this function?

It is checking the password, but when the password is valid, it is also initializing the session which is a side-effect.

You can change the name of the function to something like checkPasswordAndInitializeSession to make this effect explicit. But when you do that, you should notice that your function is actually doing two things and you should not initialize the session here.

Don't Repeat Yourself

Code repetition may be the root of all evil in software. Duplicate code means you need to change things in multiple places when there is a change in logic and it is very error prone.

Use your IDE's refactoring features and extract a method whenever you come across a repeated code segment.

Bonus

Do not leave code in comments

Please, do not. This one is serious because others who see the code will be afraid to delete it because they do not know if it is there for a reason. That commented out code will stay there for a long time. Then when variable names or method names change, it gets irrelevant but still nobody deletes it.

Just delete it. Even if it was important, there is version control for that. You can always find it.

Know your language's conventions

You should know your language's conventions in terms of spacing, comments, and naming things. There are style guides available for many languages.

For example, you should use camelCase in Java but snake_case in Python. You put opening braces on a new line in C# but you put them on the same line in Java and JavaScript.

These things change from language to language and there is no universal standard.

Her er nogle nyttige links til dig:

  • Python Style Guide
  • Googles Javascript Style Guide
  • Google Java Style Guide

Konklusion

Ren kodning er ikke en færdighed, der kan erhverves natten over. Det er en vane, der skal udvikles ved at holde disse principper i tankerne og anvende dem, når du skriver kode.

Tak fordi du tog dig tid til at læse, og jeg håber, det var nyttigt.

Hvis du er interesseret i at læse flere artikler som denne, kan du abonnere på min blog.