08:30, 28.06.2021. | PROGRAMIRANJE NIŠ

Vežbe za jasniji kod

Autor: Petar Petković, izvor: PMF Žurnal

Momak nervozno sedi za računarom, izvor: Pexels

Programeri veoma često koriste izraz “loš kod”. Ovako nazivaju svaki kod koji nije na njihovom nivou kvaliteta. Zatrpani gomilom zahteva koji trebaju brzo da se završe, ponekad, iza sebe ostavljaju loš kod. Standardan izgovor je: “Bitno da radi”. Ustvari, to je najbitnije, sve dok vas klijent ne kontaktira i promeni svoje zahteve. To su momenti kada postanete svesni koliko je kod loš i koliko će biti “skupe” izmene koje ćete morati da napravite.

Kako bi pisali bolji kod, Džef Bej je predstavio vežbe programiranja i grupisao ih u 9 pravila u svojoj knjizi The ThoughtWorks Anthology. Pridržavajući se što više ovih pravila, prirodno ćete promeniti način pisanja koda. To ne znači da morate stalno da ih se pridržavate. Pronađite ravotežu, neka od njih koristite ukoliko osećate da je tako ispravnije.

1. Jedan nivo identacije po metodi

Kada imate više od jednog nivoa identacija obično je takav kod težak za čitanje i održavanje. Morate malo dublje da ga analizirate, posebno ako ima različite uslove na različitim nivoima ili petlju unutar petlje kao u sledećem primeru:

class Board {
    public String board() {
        StringBuilder buf = new StringBuilder();

        // 0
        for (int i = 0; i < 10; i++) {
            // 1
            for (int j = 0; j < 10; j++) {
                // 2
                buf.append(data[i][j]);
            }
            buf.append("\n");
        }

        return buf.toString();
    }
}

Kako bi ispoštovali pravilo nije potrebno da smanjite kod, nego da metodu podelite na više metoda. Ovo će umnogome povećati čitljivost koda.

class Board {
    public String board() {
        StringBuilder buf = new StringBuilder();

        collectRows(buf);

        return buf.toString();
    }

    private void collectRows(StringBuilder buf) {
        for (int i = 0; i < 10; i++) {
            collectRow(buf, i);
        }
    }

    private void collectRow(StringBuilder buf, int row) {
        for (int i = 0; i < 10; i++) {
            buf.append(data[row][i]);
        }

        buf.append("\n");
    }
}

2. Ne koristite ELSE granu

Ovo pravilo se bazira na korišćenju Guards-a koji će rano vratiti rezultat metode za nepoželje ulazne vrednosti, dok će ostatak metode imati prirodan algoritam za tu metodu. Izbegavanje else grane je lako primenljivo i za uzvrat se dobija veoma elegantan kod.

public void login(String username, String password) {

    if (!userRepository.isValid(username, password)) {
        addFlash("error", "Bad credentials");
        redirect("login");
    }

    redirect("homepage");
}

3. Enkapsulirajte primitivne vrednosti i stringove

Kako bi izbegli Primitive Obsession, sve primitivne vrednost bi trebale biti enkapsulirane u objektima. Ako primitivna promenjiva ima određeno ponašanje (novac, vreme), neophodno je da se ona enkapsulira.

4. Jedna klasa po kolekciji

Kada koristite kolekciju elemenata i želite da manipulišete sa njima, potrebno je da napravite klasu koja je namenjena isključivo tome.

Svaka kolekcija ima svoju klasu i sva ponašanja koja se odnose na tu kolekciju implementiraju se u okviru klase.

5. Jedna tačka po liniji

U nazivu ovog pravila tačka predstavlja poziv metode. Ovo pravilo kaže da pozivi metoda ne trebaju biti “chainovani”. Direktno je povezano sa Law of Demeter. Objekti bi trebalo da kontaktiraju samo najbliže prijatelje (objekte).

6. Ne kratite imena

Ako se u kodu ponavljaju ista imena iznova i iznova, verovatno se radi o istoj stvari, tj. imate duplirani kod. Kada je ime metoda predugačko, to verovatno znači da ima više od jedne odgovornosti, što je loše jer ne poštuje Single Responsibility Principle.

Skraćenice mogu da dovedu do zbunjenosti, jer nije svako upoznat sa njihovim značenjem. Imenovanje je veoma bitna stvar i može značajno da poboljša kvalitet koda. Iz imena promenljive, metode ili klase treba da bude jasno šta one predstavljaju. Kada ne možete da nađete adekvatno ime, nešto verovatno nije u redu.

7. Zadržite sve entitete malim

Pravilo kaže: “Nijedna klasa preko 50 linija koda i paket preko 10 fajlova.” Ideja ovog pravila je da je velike fajlove teško čitati, teško razumeti i teško održavati.

8. Bez klasa sa više od dve promenljive

Da bi se ovo pravilo ispoštovalo, potrebno je da se primenjuje pravilo broj tri. Glavna ideja je da se razlikuju dve vrste klasa, one koje održavaju stanje pojedinačne promenjive i one koje upravljaju sa dve. Dva je proizvoljan izbor koji Vas primorava da podelite klase što više.

Grafički prikaz osmog pravila, izvor: Willian Durand

9. Bez gettera/settera

Sve dok ne koristite rezultat gettera da bi napravili neku odluku izvan objekta, korišćenje gettera je u redu. Odluke koje su donete na osnovu stanja objekta bi trebalo da se nalaze u samom objektu.

Pogledajmo primer:

// Game
private int score;

public void setScore(int score) {
    this.score = score;
}

public int getScore() {
    return score;
}

// Usage
game.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);

U navedenom primeru getter se koristi kako bi se povećao broj poena u igri. Bolje rešenje je da se obrišu getter i setter i da se doda nova metoda koja će povećavati broj poena.

// Game
public void addScore(int delta) {
    score += delta;
}

// Usage
game.addScore(ENEMY_DESTROYED_SCORE);

Neka pravila su laka za korićenje, neka su malo teža. U svakom slučaju, dobro je imati ih na umu kako bi Vaš kod bio pregledniji i lakši za održavanje.