Formátování zdrojového kódu

Nálepky:

Při psaní zdrojového kódu je dobré dodržovat jistou štábní kulturu. A okolo této kultury se vedou obrovské dohady. Používat CamelCase nebo snake_case, tabelátory nebo mezery. Otevírací závorky na stejném řádku, nebo na dalším novém. I když mám nějaké preference, pokusím se napsat článek tak, aby si každý udělal obrázek sám. Jsem si totiž moc dobře vědom, že zvyk, železná košile i prostředí dokáží, že každému vyhovuje něco jiného.

Tým, tým, tým

"Tým je vždy na prvním místě!" Tímto bych rád upozornil na fakt, že štábní kulturu je vhodné používat vždy. Existuje snad jeden jediný případ, kdy není třeba nějakou štábní kulturu dodržovat, ale i tam se to hodí.

První případ je jasný. Pokud nějaký kód udržuje a rozvijí tým, i kdyby o dvou členech, musí být kód čitelný všem. Dovolím si tvrdit že musí, protože pokud to tak není, je to základ nejednoho problému. Jenže, když na to přijde, i sám jeden programátor / programátorka je tým. Ono totiž editovat, upravovat starý kód, který je psán jako když ryje divoké prase v lese není nic, po čem jeden / jedna zrovna touží. A i kdyby to byl náhodou jen maličký projekt, co když jeho nasazení a údržba přeroste do korporátního řešení se samostatným týmem. Jeden nikdy neví co se může stát.

Dalším případem je otevřený kód. Na GitHubu a jiných severech je ho jako šafránu. A není tam jen proto, že je to vhodné pro týmovou práci. Autoři se jím chtějí pochlubit, a tam se jaksi čitelnost tak trochu očekává. Čitelný by měl být také pro Vaše případné zaměstnavatele, kteří budou tyto servery procházet, než Vám dají práci Vašich snů.

Snad jediný příklad, kdy není třeba hledět na čistotu a čitelnost kódu je práce prototypáře. Jeho kód v konečném důsledku možná ani nemá být čitelný, aby nikoho náhodou neinspiroval. Jeho kód je určen k jedné jediné věci, otestovat předpoklad, funkcionalitu, užitečnost. Po něm má přijít někdo, kdo postaví správné a čisté řešení problému.

O čem to sakra je?

Důvod - účel tohoto článku je ale přinést jistý pohled na samotnou podobu štábní kultury jako takové. Při nedávném úkolu jsem si všiml, že dřívější zvyklosti se mi stali nečitelné. Zároveň nesouhlasím s tím, že o "formátování" kódu se má starat editor. Naprosto souhlasím že editor je nástroj, který umožňuje vizualizovat zdrojový kód tak, jak je programátor zvyklý, ale nemyslím si že to znamená že programátor musí takový editor používat. Pokud by tomu tak bylo, je to určitě špatně. Napadlo mne tedy podívat se na celou problematiku od pravěku, nebo minimálně středověku. Co takhle vzít kód a editovat ho (prohlížet) v prostém textovém editoru.

Ano zcela chápu že toto už asi nikdo nedělá, ale proč by měl být nucen to nedělat? To že mám font tak malý, že se mi na obrazovku vejde 160 znaků, neznamená že jej má i někdo jiný, třeba slabozraký kolega. A co platí o počtu znaků vedle sebe, platí i o počtu řádků. Mimochodem, zkusili jste se někdy koukat na zdrojový kód na mobilu, nebo na elektronické čtečce? I to je totiž jedna forma vizualizace!

A co když se stane nějaký problém, a v danou chvíli nebude po ruce žádný schopný editor, nebo terminál s vysokým rozlišením. Chápu že to není denní chleba, ale takhle to prostě je. Zkuste si tedy zobrazit Váš kód v terminálu 80x25. V textovém editoru, bez zvýraznění syntaxe. Bez všech těch vizualizačních možností, které máte.

Následují tři ukázky obsahují mix různých stylů. A po každé ukázce z obarvením následuje i obrázek toho, jak vypadá kód v klasické konzoli 80x25 bez zvýrazňování.

test1.cc:

První příklad je specifický vysokým počtem řádků, jestli jsou zbytečné, nebo ne, nechám na Vás.

#include <list>

class
Point_t
{
    public:
        Point_t
        (
            float x,
            float y,
            float z
        ):
            x(x),
            y(y),
            z(z)
        {
        };

        ~Point_t
        (
        )
        {
        };

        float
        computeSomeMagickValue
        (
        )
        const;

        float
        computeAnotherMagickValueWithParams
        (
            const float paramA,
            const float paramB,
            const float paramC
        )
        const;


    private:
        float x;
        float y;
        float z;
};

float
Point_t::computeSomeMagickValue
(
)
const
{
    float temporaryFloatValue;
    temporaryFloatValue = this->x * this->y;
    if (temporaryFloatValue != 0.0 && this->z != 0.0)
    {
        temporaryFloatValue = temporaryFloatValue / this->z;
    }
    return temporaryFloatValue;
}

float
Point_t::computeAnotherMagickValueWithParams
(
    const float paramA,
    const float paramB,
    const float paramC
)
const
{
    float temporaryFloatValue;
    temporaryFloatValue = (this->x * paramA) + (this->y * paramB);
    if (temporaryFloatValue != 0.0 &&
        this->z != 0.0 &&
        paramC != 0.0 &&
        (this->z + paramC) != 0.0 &&
        this->computeSomeMagickValue())
    {
        return temporaryFloatValue / this->z + paramC;
    }
    else
    {
        return -1.0;
    }
}
test1.cc - Začátek třídy

test1.cc - Začátek třídy

test1.cc - Konec třídy

test1.cc - Konec třídy

test1.cc - Metoda

test1.cc - Metoda

test2.cc:

Druhý příklad jasně ukazuje, jak to vypadá, při používání řádků delších než 80 znaků, takže se na obrazovku nevejdou. Ať už to považujete za nešvar nebo ne, není bohužel ani na jednom snímku vidět, jak to vypadá, když editor řádek zalomí.

#include <list>

class Point {
    public:
        Point (float x, float y, float z): x(x), y(y), z(z)
        {};

        ~Point()
        {};

        float compute_some_magick_value () const;
        float compute_another_magick_value_with_params(const float param_a, const float param_b, const float param_c) const;

        private:
        float x;
        float y;
        float z;
};

float Point::compute_some_magick_value() const {
    float temporary_float_value;
    temporary_float_value = this->x * this->y;
    if (temporary_float_value != 0.0 && this->z != 0.0) {
        temporary_float_value = temporary_float_value / this->z;
    }
    return temporary_float_value;
}

float Point::compute_another_magick_value_with_params(const float param_a, const float param_b, const float param_c) const {
    float temporary_float_value;
    temporary_float_value = (this->x * param_a) + (this->y * param_b);
    if (temporary_float_value != 0.0 && this->z != 0.0 && param_c != 0.0 && (this->z + param_c) != 0.0 && this->compute_some_magick_value()) {
        return temporary_float_value / this->z + param_c;
    } else {
        return -1.0;
    }
}
test2.cc - Celá deklarace třídy

test2.cc - Celá deklarace třídy.

test1.cc - Obě metody

test2.cc - Obě metody.

test3.cc:

Následující kód je psaný v editoru s použitím tabelátorů o délce 4 znaky. Aniž by to byl účel, podařilo se mi míchat mezery s tabelátory, což je pak vidět na obou snímcích obrazovky souboru test3.cc . Chybu jsem nakonec nechal, neb i to se stává, v každém případě je dobré připomenout, že ať už mezery nebo tabulátory, nikdy by neměli být míchány!

#include <list>

class Point_t
{
    public:
        Point_t (float x, float y, float z)
            : x (x), y (y), z (z)
        {};

        ~Point_t ()
        {};

    float computeSomeMagickValue () const;

    float computeAnotherMagickValueWithParams (const float paramA,
                                               const float paramB,
                                               const float paramC) const;

    private:
        float x, y, z;
};

float Point_t::computeSomeMagickValue () const
{
    float temporaryFloatValue (this->x * this->y);
    if (temporaryFloatValue != 0.0 && this->z != 0.0)
    {
        temporaryFloatValue = temporaryFloatValue / this->z;
    }
    return temporaryFloatValue;
}

float Point_t::computeAnotherMagickValueWithParams (const float paramA,
                                                    const float paramB,
                                                    const float paramC) const
{
    float temporaryFloatValue ((this->x * paramA) + (this->y * paramB));
    if (temporaryFloatValue != 0.0 && this->z != 0.0 && paramC != 0.0 &&
        (this->z + paramC) != 0.0 && this->computeSomeMagickValue())
    {
        temporaryFloatValue = temporaryFloatValue / this->z + paramC;
    } else
    {
        return -1.0;
    }
}
test3.cc - Celá deklarace třídy

test3.cc - Celá deklarace třídy

test3.cc - Metoda

test3.cc - Metoda

Kód je schválně psaný hloupě, neoptimálně. V praxi by taková třída pravděpodobně neměla tak dlouhé názvy funkcí. To vše proto, aby vynikly problémy způsobené právě různým stylem psaní a formátování kódu. Původně jsem chtěl uvést i ukázku zdrojového kódu v Pythonu, ale nebylo by to úplně fér. Jednak jeho zápis vypadá prostě jinak, ale především existuje několik předpisů, jak má být kód psaný, zejména to je PEP8. Tyto předpisy definují (ne)použití tabelátoru (odsazení je v Pythonu povinné, stejně jako středník nebo závorky v C/C++). Snakecase zápis metod a proměnných, Camelcase zápis tříd, dokonce i zalamování řádků delších než 80 znaků, zápis dokumentace atd.

Co je podstatné, v kódu chybí dokumentace. Ta může kód tvořit bez barevného zvýrazňování ještě více nečitelným.

Co z toho plyne?

V každé ukázce jsem se snažil použít nějaký nešvar, ale i styl, který se mi líbí, tak aby neexistovala jasně správná ukázka. Nicméně, až budete svědky nebo účastníky diskuze na téma štábní kultura zdrojového kódu, vzpomeňte si na tento článek. A zkuste se podívat na kód z pohledu pozorovatele, čtenáře, studenta. Uživatele mobilního zařízení, nebo i na sebe sama, když jediná možnost jak rychle opravit kód je v terminálu s mizerným rozlišením v editoru, který nezná syntaxi editovaného souboru. K šířce řádků, a velikosti metod a funkcí co do počtu řádků, samozřejmě existují různá doporučení, ty zde zmiňovat nebudu.

Za diskuzi pod článkem budu velmi rád, vyvarujte se ale prosím diskuze o tabelátorech. Tento článek o nich není, byť se jich přímo dotýká.

Autor:

Diskuze

Váš komentář:

© 2017 Ondřej Tůma McBig. Ondřej Tůma | Based on: Morias | Twitter: mcbig_cz | RSS: články, twitter