Koodi kirjutatakse üks kord ja loetakse sadu kordi. Arendaja, kes funktsiooni kirjutab, on harva see, kes seda kuus kuud hiljem silub, seda uute nõuete jaoks laiendab või peab tootmisintsidendi ajal mõistma selle äärmusjuhtumeid. Iga koodi kirjutamise ajal tehtud otsus – muutuja nimi, funktsiooni pikkus, klassi struktuur – muudab järgmise lugeja töö kas lihtsamaks või raskemaks. Puhas kood on distsipliin, mis muudab selle süstemaatiliselt lihtsamaks.
Kontseptsiooni vormistas Robert C. Martin, „Uncle Bob”, teoses „ Clean Code: A Handbook of Agile Software Craftsmanship” (2008), mis on teema kanooniline viide. Martin Fowleri teos „Refactoring: Improving the Design of Existing Code” käsitleb täiendavat probleemi: mida teha, kui olemasolev kood pole puhas, aga vajab puhastamist. Koos määratlevad need kaks teost puhta koodi praktika intellektuaalse aluse. See juhend hõlmab nende peamisi põhimõtteid koos toimivate koodinäidetega kõige laialdasemalt kasutatavates keeltes, sealhulgas RPG ja PL/I arendajatele, kes haldavad ettevõtte pärandsüsteeme.
Puhtad koodirikkumised, mida te ei näe
SMART TS XL leiab keerukust, dubleerimist ja surnud koodi COBOL-is, Java-s, Pythonis, RPG-s ja mujal.
Rohkem infotMis on puhas kood?
Puhas kood on lähtekood, mida on lihtne lugeda, mõista, testida ja muuta. Selles definitsioonis viitab fraas „lihtne” päris töö tegemisele. Kood, mida kompilaator aktsepteerib, ei ole tingimata puhas kood. Kood, mis läbib kõik testid, ei ole tingimata puhas kood. Kood on puhas, kui teine arendaja, keegi, kes seda ei kirjutanud, kontekstis, mida selle kirjutamise ajal ette ei nähtud, suudab selle kavatsusest kiiresti aru saada, seda enesekindlalt muuta ja ootamatute tagajärgedeta laiendada.
Martin Fowleri definitsiooni tsiteeritakse kõige sagedamini: „Iga loll oskab kirjutada koodi, millest arvuti aru saab. Head programmeerijad kirjutavad koodi, millest inimesed aru saavad.“ Puhta koodi mõõdupuuks on inimese arusaamine, mitte masina teostus.
Puhas kood ei ole esteetika küsimus. Asi ei ole konkreetse stiilijuhendi järgimises koodi enda pärast. Asi on koodi struktuurilistes omadustes, mis määravad, kui palju pingutust iga tulevane muudatus nõuab. Puhta koodi põhimõtteid rikkuv koodibaas kogub pidevalt tehnilist võlga ehk varasemate otseteede liitkulusid, kuni iga uus funktsioon nõuab enne uue funktsiooni lisamist olemasoleva keerukuse mõistmist ja hoolikat navigeerimist.
Puhta koodi põhimõtted: kiirjuhend
Robert C. Martini puhta koodi põhimõtted saab kokku võtta tegutsemiskõlblike suuniste kogumina. Allolev tabel seob iga põhimõtte selle põhireegli ja probleemiga, mida see ennetab:
| Põhimõte | Põhireegel | Probleem, mida see ennetab |
|---|---|---|
| Tähenduslikud nimed | Nimed peaksid paljastama kavatsuse, muutujad, funktsioonid ja klassid | Kognitiivsed lisakulud dekodeerivad mida x, tmpvõi obj tegelikult esindab |
| Väikesed funktsioonid | Funktsioonid teevad ühte asja; mahuvad ühele ekraanile | Testimata, loetamatud monoliidid, mis segavad vastutust |
| Üksikvastutus | Igal klassil/moodulil on üks põhjus muutumiseks | Jumalaklassid, mis purunevad, kui mõni tosinast omavahel mitteseotud asjast muutub |
| KUIV (Ära korda ennast) | Igal teadmisel on üks esitusviis | Veaparandused rakendati ühes eksemplaris, kuid mitte teistes; loogika hälve |
| KISS (Hoia see lihtne) | Eelista kõige lihtsamat ja toimivamat lahendust | Üleinsenereeritud kood, mis lahendab probleeme, mida kellelgi pole olnud |
| YAGNI (teil pole seda vaja) | Ärge looge funktsioone enne, kui neid vaja on | Surnud spekulatiivne kood, mis lisab keerukust ilma igasuguse kasuta |
| Avatud/suletud põhimõte | Avatud laiendamiseks, suletud muutmiseks | Kood, mis rikub olemasoleva käitumise uue käitumise lisamisel |
| Murede lahutamine | Erinevad kohustused erinevates kohtades | Sassis kood, kus ühe asja muutmine lõhub omavahel mitteseotud asju |
| Väldi kommentaare küsimusele „miks“; kasuta neid küsimusele „miks“ | Kood selgitab mida; kommentaarid selgitavad miks | Vananenud kommentaarid, mis eksitavad rohkem kui annavad teavet |
| Skautide reegel | Jäta kood puhtamaks, kui sa selle leidsid | Järkjärguline kvaliteedi langus järkjärgulise hooletussejätmise tõttu |
Puhta koodi põhiprintsiibid selgitatud
KUIV, ära korda ennast
DRY on põhimõte, mille kohaselt peab igal teadmisel süsteemis olema üksainus, üheselt mõistetav ja autoriteetne esitus. Kui sama loogika esineb mitmes kohas, siis need esitused lahknevad paratamatult. Ärireegli muudatusest saab otsingu-ja-asenduse operatsioon mitmes failis ning ühe koopia puudumine tekitab vea.
DRY kehtib enama kui lihtsalt kopeeritud-kleebitud koodi kohta. See kehtib konfiguratsiooni, dokumentatsiooni ja andmeskeemide kohta. Kui sama teavet tuleb säilitada kahes kohas, olete DRY reegleid rikkunud olenemata sellest, kas mõni kood on sõna-sõnalt kopeeritud või mitte.
KISS, hoia see lihtne
KISS väidab, et süsteemid toimivad kõige paremini siis, kui neid hoitakse lihtsana, ning et lihtsus peaks olema peamine disainieesmärk. Keerukus ei ole märk keerukusest, vaid märk sellest, et midagi oleks saanud selgemini väljendada.
Praktiline tähendus: kui kaks lahendust lahendavad sama probleemi, eelista lihtsamat. Keerulisem lahendus võib käsitleda äärejuhtumeid, millega sa pole veel kokku puutunud. See muudab koodi kindlasti raskemini mõistetavaks kõigile, kes sellega kokku puutuvad.
YAGNI, sa ei vaja seda
YAGNI ei soovita funktsionaalsust lisada enne, kui seda vaja läheb. See on vastus üldisele soovile luua paindlikke ja laiendatavaid süsteeme tulevaste nõuete jaoks, mis kunagi ei realiseeru. Iga abstraktsioon, liides ja konfiguratsioonivõimalus, mis eksisteerib hüpoteetilise tulevase kasutusjuhtumi jaoks, on kognitiivne lisakoormus igale arendajale, kes täna koodi loeb.
Tähenduslikud nimed
Nimed on lähtekoodi peamine suhtlusmehhanism. Funktsioon nimega process() ei anna midagi selle kohta, mida see töötleb, millal või mida see tagastab. Funktsioon nimega calculateMonthlyInterest() suhtleb täpselt.
Nime peamised testid: Kas sa saad aru, mida see esindab ilma selle implementatsiooni lugemata? Kas nimi paljastab selle eesmärgi, parameetrid ja tagastusväärtuse? Kas vajaksid kommentaari, mis selgitaks, mida see teeb?
Väikesed funktsioonid
Robert C. Martini rusikareegel: funktsioonid peaksid olema väikesed, väiksemad kui arvate vajalikuks. Funktsiooni, mis teeb ühte asja, saab selgelt nimetada, testida eraldi ja mõista ilma selle implementatsiooni lugemata. Funktsioon, mis teeb mitut asja, nõuab nende kõigi samaaegset mõistmist.
Funktsioonidele rakendatud ühe vastutuse printsiip: funktsioon peaks tegema ühte asja, tegema seda hästi ja tegema ainult seda. Kui funktsiooni tegevuse kirjeldamiseks on vaja sõna „ja“, teeb see ilmselt liiga palju.
Puhas kood Javas
Java paljusõnalisus muudab puhta koodi distsipliini eriti oluliseks. Keele nõutav standardne struktuur võib koodi eesmärgi varjata, kui seda hoolikalt ei hallata.
Java
// Before: unclear names, mixed responsibilities, magic numbers
public double calc(int x, int y) {
double r = 0;
if (y > 1000) {
r = x * y * 0.1;
} else {
r = x * y * 0.05;
}
return r;
}
// After: meaningful names, single responsibility, named constants
private static final double PREMIUM_DISCOUNT_RATE = 0.10;
private static final double STANDARD_DISCOUNT_RATE = 0.05;
private static final int PREMIUM_THRESHOLD = 1000;
public double calculateDiscount(int quantity, int unitPrice) {
double subtotal = quantity * unitPrice;
return isPremiumOrder(unitPrice)
? subtotal * PREMIUM_DISCOUNT_RATE
: subtotal * STANDARD_DISCOUNT_RATE;
}
private boolean isPremiumOrder(int unitPrice) {
return unitPrice > PREMIUM_THRESHOLD;
}
Java puhta koodi peamised tavad: eelistada komponeerimist pärimisele, kasutada andmetöötluseks vooge pikasõnaliste tsüklite asemel, eraldada maagilisi numbreid nimega konstantidest ja hoida klassid keskendunud ühele vastutusele. Robert C. Martini Java puhta koodi põhimõtted hõlmavad reeglit, et klassid peaksid olema väikesed, mõõdetuna mitte ridade, vaid vastutuste arvus.
Java
// Clean Java: streams over imperative loops
List<String> activeUserEmails = users.stream()
.filter(User::isActive)
.map(User::getEmail)
.collect(Collectors.toList());
Puhas kood Pythonis
Pythoni disainifilosoofia, mille kohaselt on selgesõnaline parem kui kaudne ja lihtne parem kui keeruline, on loomulikult kooskõlas puhta koodi põhimõtetega. PEP 8 on Pythoni ametlik stiilijuhend ja puhta Pythoni koodi alus.
püüton
# Before: vague names, long function, no separation
def do_stuff(d):
res = []
for i in d:
if i['a'] > 18:
res.append(i['n'].upper())
return res
# After: meaningful names, separated concerns, Pythonic style
def get_adult_names_uppercase(users: list[dict]) -> list[str]:
return [
user["name"].upper()
for user in users
if user["age"] > 18
]
püüton
# Clean Python: context managers for resource handling
# Before: manual, error-prone
f = open("data.txt")
data = f.read()
f.close()
# After: guaranteed cleanup, self-documenting intent
with open("data.txt") as f:
data = f.read()
Pythoni puhas kood kasutab lihtsate teisenduste jaoks käsitsi tehtavate tsüklite asemel loendimõistmist, isedokumenteerivate funktsioonide signatuuride jaoks tüübivihjeid, ressursside haldamiseks kontekstihaldureid ning struktureeritud andmete jaoks andmeklasse või nimega tupleid paljaste sõnastike asemel.
Puhas kood JavaScriptis ja TypeScriptis
JavaScripti paindlikkus on nii selle tugevus kui ka peamine puhta koodi väljakutse. Ilma distsipliinita kogunevad JavaScripti koodibaasid ebajärjekindlatesse mustritesse, varjatud tüübipiirangutesse ja sassis tagasihelistusahelatesse.
JavaScript
// Before: var, callback hell, no error handling
function getUser(id, cb) {
db.query('SELECT * FROM users WHERE id = ' + id, function(err, rows) {
if (err) cb(err);
cb(null, rows[0]);
});
}
// After: async/await, parameterized query, proper error handling
async function getUserById(userId: number): Promise<User | null> {
const [rows] = await db.execute(
'SELECT * FROM users WHERE id = ?',
[userId]
);
return rows[0] ?? null;
}
masinakiri
// Clean TypeScript: explicit types replace implicit any
// Before
function process(data) {
return data.map(x => x.v * 2);
}
// After
interface DataPoint {
value: number;
label: string;
}
function doubleValues(dataPoints: DataPoint[]): number[] {
return dataPoints.map(point => point.value * 2);
}
Puhas JavaScripti kasutusala const algselt, let kui ümberköitmine on vajalik ja mitte kunagi varPuhtad funktsioonid, sama sisend annab alati sama väljundi, ilma kõrvalmõjudeta, on JavaScripti loogika kõige puhtamad ehituskivid.
Puhas kood C# keeles
C# pakub võimsaid funktsioone puhta ja väljendusrikka koodi kirjutamiseks. Keele evolutsioon, LINQ, kirjed, mustrite sobitamine, nullitavad viitetüübid, liigub järjepidevalt deklaratiivsema ja loetavama süntaksi suunas.
csharp
// Before: magic numbers, verbose loop, mutable state
public double CalculateTotal(List<OrderItem> items)
{
double total = 0;
foreach (var item in items)
{
if (item.Quantity > 10)
total += item.UnitPrice * item.Quantity * 0.9;
else
total += item.UnitPrice * item.Quantity;
}
return total;
}
// After: named constant, LINQ, single expression
private const double BulkDiscountRate = 0.9;
private const int BulkDiscountThreshold = 10;
public double CalculateTotal(IEnumerable<OrderItem> items) =>
items.Sum(item => item.Quantity > BulkDiscountThreshold
? item.UnitPrice * item.Quantity * BulkDiscountRate
: item.UnitPrice * item.Quantity);
C# puhta koodi põhimõtted: kasutage kapseldamiseks avalike väljade asemel omadusi, kasutage deklaratiivsete andmetoimingute jaoks LINQ-d, kasutage muutumatute andmestruktuuride jaoks kirjeid, eelistage meetodi signatuurides liideseid konkreetsetele tüüpidele ja kasutage nullitavaid viitetüüpe (string? vs string) nullturvalisuse selgesõnaliseks muutmiseks.
Puhas kood Kotlinis
Kotlini disain vähendab spetsiifiliselt Java puhtana hoidmist raskendavat standardmalli, lisades samal ajal funktsioone, andmeklasse, laiendusfunktsioone ja nullturvalisust, mis toetavad puhast koodi loomulikult.
kotlin
// Before: verbose Java-style Kotlin
class User {
var name: String = ""
var email: String = ""
var age: Int = 0
}
fun processUsers(users: List<User>): List<String> {
val result = mutableListOf<String>()
for (user in users) {
if (user.age >= 18) {
result.add(user.email)
}
}
return result
}
// After: idiomatic clean Kotlin
data class User(val name: String, val email: String, val age: Int)
fun getAdultEmails(users: List<User>): List<String> =
users.filter { it.age >= 18 }.map { it.email }
Kotlini data class pakub automaatselt equals'i, hashCode'i, copy'i ja toString'i, kõrvaldades malli, mis muudab Java andmeklassid pikaks ja veaohtlikuks. Laiendusfunktsioonid võimaldavad teil olemasolevatele klassidele lisada puhtaid utiliidimeetodeid ilma pärimiseta.
Puhas kood rollimängudes ja mängudes/interpretatsioonides: pärandkeeled, tänapäevased põhimõtted
Puhta koodi põhimõtted kehtivad igale programmeerimiskeelele, sealhulgas ettevõttekeeltele, mis käitavad finantssüsteeme, kindlustusplatvorme ja valitsusrakendusi kogu maailmas. RPG-d (Report Program Generator) ja PL/I-d hallatakse paljudes organisatsioonides endiselt aktiivselt ning sama distsipliin, mis muudab Java või Pythoni puhtaks, muudab RPG ja PL/I jätkusuutlikuks.
Puhas kood RPG-s (ILE RPG) :
RPG
// Before: cryptic two-character names, magic numbers
C EVAL D = Q * P * 1.05
C IF Q > 100
C EVAL D = Q * P * 0.95
C ENDIF
// After: meaningful names, named constants, clear intent
/free
dcl-c BULK_DISCOUNT_THRESHOLD 100;
dcl-c BULK_DISCOUNT_RATE 0.95;
dcl-c STANDARD_RATE 1.05;
dcl-proc CalculateOrderTotal;
dcl-pi *N packed(15:2);
quantity packed(7:0) value;
unitPrice packed(9:2) value;
end-pi;
if quantity > BULK_DISCOUNT_THRESHOLD;
return quantity * unitPrice * BULK_DISCOUNT_RATE;
else;
return quantity * unitPrice * STANDARD_RATE;
endif;
end-proc;
/end-free
Peamised puhta rollimängu tavad: kasutage ILE RPG vaba vormingut (/free) loetavuse huvides fikseeritud vormingu asemel süntaksit, nimetage protseduurid kirjeldavalt, asendage kõvakodeeritud väärtused nimega konstantidega, kasutades dcl-cja lagundage pikad programmid fokuseeritud protseduurideks, kasutades dcl-proc.
Puhas kood PL/I-s :
korda
/* Before: single-letter names, no structure */
CALC: PROC(X, Y) RETURNS(FLOAT);
DCL (X, Y, R) FLOAT;
IF Y > 1000 THEN R = X * Y * 0.1;
ELSE R = X * Y * 0.05;
RETURN(R);
END CALC;
/* After: meaningful names, named constants, clear intent */
DCL PREMIUM_THRESHOLD FIXED DECIMAL(7) INIT(1000);
DCL PREMIUM_RATE FLOAT INIT(0.10);
DCL STANDARD_RATE FLOAT INIT(0.05);
CALCULATE_DISCOUNT: PROC(QUANTITY, UNIT_PRICE) RETURNS(FLOAT);
DCL (QUANTITY, UNIT_PRICE) FLOAT;
DCL SUBTOTAL FLOAT;
SUBTOTAL = QUANTITY * UNIT_PRICE;
IF UNIT_PRICE > PREMIUM_THRESHOLD
THEN RETURN(SUBTOTAL * PREMIUM_RATE);
ELSE RETURN(SUBTOTAL * STANDARD_RATE);
END CALCULATE_DISCOUNT;
PL/I puhta koodi põhimõtted peegeldavad tänapäevaste keelte põhimõtteid: tähendusrikkad identifikaatorid (PL/I 31 tähemärgi limiit on kirjeldavate nimede jaoks piisav), nimetatud konstandid maagiliste numbrite asemel, ühele ülesandele keskenduvad protseduurid ja selgesõnaline veatöötlus ON-tingimuste süsteemi abil.
Puhaskoodi tööriistad ja staatiline analüüs
Puhta koodi põhimõtete käsitsi rakendamine koodi ülevaatuse kaudu on vajalik, kuid mitte piisav suures mahus. Staatilise analüüsi tööriistad jõustavad puhta koodi mõõdikuid automaatselt, märkides rikkumised enne nende ühendamist.
| Vahend | Keeled | Mida see jõustab |
|---|---|---|
| SonarQube / SonarCloud | 30 + keeled | Keerukus, dubleerimine, koodilõhnad, turvalisus |
| Tšekistiil | Java | Nimekonventsioonid, vormindamine, struktuur |
| PMD | Java, Apex | Duplikaatkood, kasutamata muutujad, keerukus |
| ESLint + TypeScript-eslint | JavaScript, TypeScript | Stiil, keerukus, kasutamata kood, asünkroonsed mustrid |
| Pylint + Radoon | Python | PEP 8, keerukus, hooldatavuse indeks |
| ReSharper | C# | Koodistiil, üleliigne kood, refaktoreerimise soovitused |
| Clippy | Rust | Idiomaatilised mustrid, levinud vead |
| SMART TS XL | COBOL, RPG, PL/I, Java, Python ja palju muud | Keelteülene keerukus, dubleerimine, surnud kood |
Kõige levinumad puhta koodi mõõdikud, mida tööriistad mõõdavad, on tsüklomaatiline keerukus (otsustusharude arv, üle 10 on hoiatus, üle 20 on kriitiline), kognitiivne keerukus (kui raske on koodi mõista, SonarQube'ile omane mõõdik, mis parandab tsüklomaatilist keerukust loetavuse mõõtmiseks) ja dubleerimise määr (dubleeritud koodi protsent, üle 3% väärib tähelepanu).
Kuidas SMART TS XL Jõustab puhta koodi kõigis ettevõtte koodibaasides
Ülaltoodud puhta koodi tööriistad töötavad ühe keele piires. Ettevõttekeskkondades, kus Java teenused, Pythoni torujuhtmed, COBOL-i partiiprogrammid, RPG-moodulid ja JCL-i töövood eksisteerivad koos, tuleb iga keele puhta koodi rikkumisi mõõta samaaegselt ning komponentide vahelised seosed keelte lõikes on sama olulised kui kvaliteet iga üksiku faili piires.
SMART TS XL'S staatilise koodi analüüs rakendab puhta koodi mõõdikuid samaaegselt kõigis keskkonnas olevates keeltes. Tsüklomaatilise keerukuse, dubleerimise määrade, surnud koodi tuvastamise ja struktuurilise sidumise mõõdikud arvutatakse COBOL-programmide jaoks sama metoodika abil nagu Java-klasside puhul, luues võrreldavad ja ühtsed kvaliteedinäitajad kogu rakenduste portfellis.
Mõjuanalüüsi võimalus muudab puhta koodi rikkumised arhitektuurilisel tasandil rakendatavaks: kui COBOL-lõik on tugevalt seotud kümnete teiste programmidega, näitab mõjuanalüüs täpselt , millised komponendid on mõjutatud enne mis tahes refaktoriseerimise alustamist. See muudab suurtes koodibaasides meeskondade kogetava refaktoriseerimise paralüüsi struktureeritud ja määratletud ulatusega parandusprogrammiks.
Rakendussõltuvuste kaardistamine tuvastab puhta koodi arhitektuurilised rikkumised süsteemi tasandil: millised komponendid on ettevõtte tasandil muutunud jumalaklassideks, kus ringsõltuvused rikuvad probleemide eraldamist keelepiiride vahel ja kus sama äriloogika on iseseisvalt rakendatud mitmes süsteemis ilma, et kumbki koopia oleks teisest teadlik. See keelteülene DRY-rikkumine, kus sama ärireeglit hoitakse eraldi COBOL-programmis, Java-teenuses ja Pythoni torujuhtmes, on ettevõtte süsteemides kõige kallim puhta koodi rikkumise kategooria ning see on nähtamatu ühelegi ühe keele tööriistale.
Meeskondadele, kes rakendavad puhta koodi põhimõtteid pärand moderniseerimine programmid, SMART TS XL pakub refaktorimiseelset analüüsi, mis muudab töö teostatavaks: surnud kood jäetakse enne teisendamise algust ulatusest välja, kõige keerukamad komponendid tuvastatakse prioriteetse tähelepanu saamiseks ja täielik sõltuvusgraafik on saadaval enne muudatuste tegemist.
Puhas kood on meeskonna distsipliin, mitte individuaalne praktika
Selle juhendi põhimõtteid on lihtsam sõnastada kui säilitada. Iga arendaja saab iseseisvalt puhta funktsiooni kirjutada. Väljakutse seisneb puhta koodi säilitamises meeskonnas, ajas ja koodibaasis, mis kasvab samal ajal, kui selle kaastöötajad vahetuvad. See nõuab kolme asja: ühiseid standardeid, mida kõik teavad ja millega on nõustunud; tööriistu, mis neid standardeid automaatselt jõustavad; ja järkjärgulise täiustamise kultuuri – skautide reegli järjepidevat rakendamist, mis jätab koodi iga osa veidi puhtamaks, kui see algselt oli.
Robert C. Martini põhimõte on siiani kõige kasulikum: „Puhas kood näeb alati välja nagu oleks selle kirjutanud keegi, kes hoolib.“ Tõend selle kohta, et keegi hoolis, ei ole vigade puudumine, vaid loetavate nimede olemasolu, fokuseeritud funktsioonid, selge struktuur ja üllatuste puudumine. Need tõendid teevadki koodibaasist töötamist, panustamist ja hooldamist väärt aastate jooksul ja meeskonnavahetuste käigus, mida iga edukas süsteem kogub.


