Kódolási stílus irányelvek

Perl
Formázás
Üres karakterek
A sorok hossza
Szóközök és zárójelek
Forráskód fejléc és karakterkódolás
A Perl nyelv használata
Vezérlési folyamat
Néhány beépített Perl szubrutin használatának korlátozása
Reguláris kifejezések
Elnevezés
Változók
Szubrutinok
Csomagok
Jó dokumentáció írása
Perldoc
Kódmagyarázatok
Adatbázis kölcsönhatás
SQL-utasítások deklarációja
Visszatérés hibák esetén
Korlát használata
A while ciklus használata
JavaScript
Böngészőkezelés
Könyvtárszerkezet
Harmadik féltől származó kód
Változók
Függvények
Névterek
Kódmagyarázatok
Eseménykezelés
CSS
Szerkezet
Stílus

Az OTRS projekt következetes fejlesztésének megtartása érdekében irányelveket fektettünk le a stílusra vonatkozóan a különböző programnyelvekhez.

Perl

Formázás

Üres karakterek

TABULÁTOR: 4 szóközt használunk. Példa a zárójelekre:

if ($Feltétel) {
    Izé();
}
else {
    Bigyó();
}

while ($Feltétel == 1) {
    Izé();
}
                
                

A sorok hossza

A sorok általában nem lehetnek hosszabbak 120 karakternél, hacsak ez különleges okok miatt nem szükséges.

Szóközök és zárójelek

A jobb olvashatóság érdekében szóközöket használunk a kulcsszavak és a nyitó zárójelek között.

if ()...
for ()...
                
                

Ha csak egy egyedülálló változó van, akkor a zárójelek belül szóközök nélkül veszik körbe a változót.

if ($Feltétel) { ... }

# e helyett

if ( $Feltétel ) { ... }
                
                

Ha a feltétel nem csak egy egyedülálló változó, akkor szóközöket használunk a zárójelek és a feltétel között. És továbbra is szóköz van a kulcsszó (például if) és a nyitó zárójel között.

if ( $Feltétel && $ABC ) { ... }
                
                

Ne feledje, hogy a Perl beépített függvényeinél nem használunk zárójeleket:

chomp $Variable;
                
                

Forráskód fejléc és karakterkódolás

Csatolja hozzá a következő fejlécet minden egyes forrásfájlhoz. A forrásfájlok UTF-8 karakterkódolással vannak elmentve.

# --
# (file name) - a short description what it does
# Copyright (C) 2001-2018 OTRS AG, https://otrs.com/
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (GPL). If you
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --
                
                

A végrehajtható fájloknak (*.pl) különleges fejlécük van.

#!/usr/bin/perl
# --
# (file name) - a short description what it does
# Copyright (C) 2001-2018 OTRS AG, https://otrs.com/
# --
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --
                
                

A Perl nyelv használata

Vezérlési folyamat
Feltételek

A feltételek meglehetősen összetettek lehetnek, és lehetnek „láncolt” feltételek is (logikai „és” vagy „vagy” operátorral összekapcsolva). Az OTRS kódolásakor tisztában kell lennie számos helyzettel.

A bevált Perl gyakorlatok azt mondják, hogy a magas precedenciájú operátorokat (&& és ||) nem kellene keverni az alacsony precedenciájú operátorokkal (and és or). A zűrzavar elkerülése érdekében mindig a magas precedenciájú operátorokat használjuk.

if ( $Condition1 && $Condition2 ) { ... }

# e helyett

if ( $Condition and $Condition2 ) { ... }
                    
                    

Ez azt jelenti, hogy tisztában kell lennie a buktatókkal. Néha zárójeleket kell használnia, hogy világossá tegye, mit szeretne.

Ha hosszú feltételei vannak (a sor 120 karakternél hosszabb), akkor több sorra kell tördelnie azt. Továbbá a feltételek kezdete egy új sorban van (nem az if sorában).

if (
    $Feltétel1
    && $Feltétel2
    )
{ ... }

# e helyett:

if ( $Feltétel1
    && $Feltétel2
    )
{ ... }
                    
                    

Jegyezze meg azt is, hogy a jobboldali zárójel egyedül áll a sorban, valamint a baloldali kapcsos zárójel szintén új sorban van, és ugyanolyan behúzással rendelkezik mint az if. Az operátorok egy új sor elején vannak! A következő példák bemutatják, hogyan kell ezt csinálni…

if (
    $XMLHash[0]->{otrs_stats}[1]{StatType}[1]{Content}
    && $XMLHash[0]->{otrs_stats}[1]{StatType}[1]{Content} eq 'static'
    )
{ ... }

if ( $TemplateName eq 'AgentTicketCustomer' ) {
    ...
}

if (
    ( $Param{Section} eq 'Xaxis' || $Param{Section} eq 'All' )
    && $StatData{StatType} eq 'dynamic'
    )
{ ... }

if (
    $Self->{TimeObject}->TimeStamp2SystemTime( String => $Cell->{TimeStop} )
    > $Self->{TimeObject}->TimeStamp2SystemTime(
        String => $ValueSeries{$Row}{$TimeStop}
    )
    || $Self->{TimeObject}->TimeStamp2SystemTime( String => $Cell->{TimeStart} )
    < $Self->{TimeObject}->TimeStamp2SystemTime(
        String => $ValueSeries{$Row}{$TimeStart}
    )
    )
{ ... }
                    
                    

Hátul álló if

Általánosan azért használunk „hátul álló if” utasításokat, hogy csökkentsük a szintek számát. De ne használjuk többsoros utasításoknál, és csak akkor megengedett, amikor visszatérési utasításokat hoz magával a függvény, vagy egy ciklus befejezéséhez, illetve a következő iterációra való ugráshoz.

Ez helyes:

next ITEM if !$ItemId;
                    
                    

Ez hibás:

return $Self->{LogObject}->Log(
    Priority => 'error',
    Message  => 'ItemID szükséges!',
) if !$ItemId;
                    
                    

Ez kevésbé karbantartható ennél:

if( !$ItemId ) {
    $Self->{LogObject}->Log( ... );
    return;
}
                    
                    

Ez helyes:

for my $Needed (1..10) {
    next if $Needed == 5;
    last  if $Needed == 9;
}
                    
                    

Ez hibás:

my $Var = 1 if $Something == 'Yes';
                    
                    

Néhány beépített Perl szubrutin használatának korlátozása

A Perl néhány beépített szubrutinját nem lehet használni semmilyen helyen:

  • Ne használja a die és exit szubrutinokat a .pm fájlokban.

  • Ne használja a Dumper függvényt a kiadott fájlokban.

  • Ne használja a print utasítást a .pm fájlokban.

  • Ne használja a require kulcsszót, inkább használja a Main::Require() metódust.

  • Használja a TimeObject függvényeit az olyan beépített függvények helyett, mint például a time(), localtime(), stb.

Reguláris kifejezések

A reguláris kifejezéseknél mindig kapcsos zárójelekkel használjuk az m// operátort elválasztóként. Használjuk az x, m és s módosítókat is. Az x módosítók lehetővé teszik a reguláris kifejezések megjegyzéssel történő ellátását, és szóközök használatát a logikai csoportok „csoportosításához”.

$Date =~ m{ \A \d{4} - \d{2} - \d{2} \z }xms
$Date =~ m{
    \A      # a szöveg kezdete
    \d{4} - # év
    \d{2} - # hónap
    [^\n]   # minden, kivéve az új sort
    #..
}xms;
    
                

Mivel a szóköznek többé nincs különleges jelentése, ezért egy egyedüli karakterosztályt kell használnia egy egyedülálló szóköz illesztéséhez ([ ]). Ha akármennyi szóközre szeretne illeszteni, akkor azt a \s használatával teheti meg.

A reguláris kifejezésben a pont (.) tartalmazza az új sort (minthogy az s módosító nélküli reguláris kifejezésben a pont azt jelenti, hogy „minden, kivéve az új sor”). Ha bármire szeretne illeszteni az új sort kivéve, akkor a tagadott egyedüli karakterosztályt kell használnia ([^\n]).

$Text =~ m{
    Teszt
    [ ]    # itt szóköznek kell lennie a „Teszt” és a „Regex” között
    Regex
}xms;
    

Elnevezés

A neveket és a megjegyzéseket angolul kell írni. A változókat, objektumokat és metódusokat leíró főnevekkel vagy főnévi igenevekkel írjuk úgy, hogy az első betű nagybetűs legyen (CamelCase).

A neveknek annyira leírónak kell lenniük, amennyire csak lehetséges. Az olvasónak egy név alapján meg kell tudni mondania, hogy az mit jelent anélkül, hogy túl mélyre ásná magát a kódban. Például használja a $ConfigItemID nevet az $ID helyett. Példák: @TicktIDs, $Output, StateSet(), stb.

Változók
Deklaráció

Ha több változója van, akkor deklarálhatja azokat egyetlen sorban, ha azok „összetartoznak”:

my ($Minute, $Hour, $Year);

                    

Egyébként tördelje azokat külön sorokba:


my $Minute;
my $ID;
                    
                    

Ne állítson be undef vagy '' kezdeti értéket a deklarációban, ugyanis ez elrejtheti a hibákat a kódban.

my $Variable = undef;

# ugyanaz mint

my $Variable;
                    
                    

Akkor állíthat be egy változót '' értékre, ha szövegeket szeretne összefűzni:

my $SqlStatement = '';
for my $Part ( @Parts ) {
    $SqlStatement .= $Part;
}
                    
                    

Egyébként „előkészítetlen” figyelmeztetést kaphat.

Szubrutinok
Paraméterek kezelése

A szubrutinoknak átadott paraméterek lekéréséhez az OTRS normális esetben a %Param kivonatot használja (nem a %Params kivonatot). Ez jobban olvasható kódot eredményez, mivel minden esetben tudjuk, hogy amikor %Param kivonatot használjuk a szubrutin kódokban, akkor paraméterkivonat került átadásra a szubrutinnak.

Csak néhány kivételnél kell a paraméterek szabályos listáját használni. Így el szeretnénk kerülni az ehhez hasonlókat:

sub TestSub {
    my ( $Self, $Param1, $Param2 ) = @_;
}
                    
                    

Inkább ezt szeretnénk használni:

sub TestSub {
    my ( $Self, %Param ) = @_;
}
                    
                    

Ennek számos előnye van: nem kell megváltoztatnunk a kódot a szubrutinban, amikor egy új paramétert kell átadni, és egy elnevezett paraméterekkel rendelkező függvény hívása sokkal olvashatóbb.

Több elnevezett paraméter

Ha egy függvényhívás egynél több elnevezett paramétert igényel, akkor tördelje azokat több sorba:

    $Self->{LogObject}->Log(
        Priority => 'error',
        Message  => "Need $Needed!",
    );
                    

E helyett:

    $Self->{LogObject}->Log( Priority => 'error', Message  => "Need $Needed!", );
                    

return utasítások

A szubrutinoknak rendelkezniük kell egy return utasítással. Az explicit return utasítás előnyben részesített az implicit módszernél (az utolsó utasítás eredménye a szubrutinban), mivel ez tisztázza, hogy mit ad vissza a szubrutin.

sub TestSub {
    ...
    return; # undef visszaadása, de nem az utolsó utasítás eredménye
}
                    
                    

Explicit visszatérési értékek

Az explicit visszatérési értékek azt jelentik, hogy nem kell egy return utasítást tenni egy szubrutinhívást követően.

return $Self->{DBObject}->Do( ... );
                    
                    

A következő példa jobb, mivel ez explicit módon megmondja, hogy mi kerül visszaadásra. A fenti példával az olvasó nem tudja, hogy mi a visszatérési érték, mivel nem tudhatja, hogy a Do() mit ad vissza.

return if !$Self->{DBObject}->Do( ... );
return 1;
                    
                    

Ha egy szubrutin eredményét hozzárendeli egy változóhoz, akkor egy „jó” változónév jelzi, hogy mi lett visszaadva:

my $SuccessfulInsert = $Self->{DBObject}->Do( ... );
return $SuccessfulInsert;
                    
                    

Csomagok
use utasítások

A use strict és use warnings utasításoknak kell az első két „use”-nak lennie a modulban. Ez helyes:

package Kernel::System::ITSMConfigItem::History;

use strict;
use warnings;

use Kernel::System::User;
use Kernel::System::Time;
                    
                    

Ez hibás:

package Kernel::System::ITSMConfigItem::History;

use Kernel::System::User;
use Kernel::System::Time;

use strict;
use warnings;
                    
                    

Objektumok és azok lefoglalása

Az OTRS-ben sok objektum érhető el. De nem kell minden egyes objektumot használnia minden fájlban az előtétprogram/háttérprogram elválasztásának megtartásához.

  • Ne használja a LayoutObject objektumot az alapmodulokban (Kernel/System).

  • Ne használja a ParamObject objektumot az alapmodulokban (Kernel/System).

  • Ne használja a DBObject objektumot az előtétprogram modulokban (Kernel/Modules).

Jó dokumentáció írása

Perldoc
Szubrutinok dokumentálása

A szubrutinokat mindig dokumentálni kell. A dokumentum tartalmaz egy általános leírást arról, hogy mit csinál a szubrutin, egy minta szubrutinhívást, és hogy mit ad vissza a szubrutin. Ezeknek ebben a sorrendben kell lenniük. Egy minta dokumentáció így néz ki:

=item LastTimeObjectChanged()

calculates the last time the object was changed. It returns a hash reference with
    information about the object and the time.

    my $Info = $Object->LastTimeObjectChanged(
        Param => 'Value',
    );

This returns something like:

    my $Info = {
        ConfigItemID    => 1234,
        HistoryType     => 'foo',
        LastTimeChanged => '08.10.2009',
    };

=cut
                    

Lemásolhat és beilleszthet egy Data::Dumper kimenetet a visszatérési értékekhez.

Kódmagyarázatok

Általánosságban meg kell próbálni olvashatóan és önmagát magyarázóan írni a kódot, amennyire csak lehetséges. Ne írjon megjegyzést annak magyarázásához, hogy a nyilvánvaló kód mit csinál, mert az szükségtelen megkettőzés. A jó megjegyzéseknek azt kell elmagyarázniuk, hogy miért van valami a kódban, mik a lehetséges mellékhatások és bármi egyéb, amely különleges lehet vagy szokatlanul bonyolult a kóddal kapcsolatban.

Ragaszkodjon a következő irányelvekhez:

Tegye a kódot annyira olvashatóvá, hogy ne legyen szükség magyarázatra, ha ez lehetséges.

Mindig vonzóbb a kódot úgy írni, hogy nagyon olvasható és önmagát magyarázó legyen, például pontos változónevekkel és függvénynevekkel.

Ne mondja el, amit a kód is elmond (száraz).

Ne ismételjen (nyilvánvaló) kódot a magyarázatokban.

# HIBÁS:

# beállítási objektum lekérése
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
                        
Azt dokumentálja, hogy a kód miért van ott, és ne azt, hogy hogyan működik.

Általában a kódmagyarázatoknak a kód célját kellene elmagyarázniuk, és nem azt, hogy részletesen hogyan működik. Lehetnek kivételek különösen bonyolult kódnál, de ebben az esetben egy átszerkesztés lenne dicséretes, hogy olvashatóbb legyen.

Dokumentálja a buktatókat.

Mindent dokumentálni kell, ami nem világos, furfangos vagy amit összerakott a fejlesztés során.

Használjon teljes soros mondatszerű magyarázatokat az algoritmus bekezdéseinek dokumentálásához.

Mindig teljes mondatokat használjon (első betűt nagybetűvel írva és központozással). Egy mondat következő sorait be kell húzni.

# Annak ellenőrzése, hogy meg lett-e adva objektumnév.
if ( !$_[1] ) {
    $_[0]->_DieWithError(
        Error => "Hiba: hiányzó paraméter (objektumnév)",
    );
}

# Az objektum rögzítése, amelyet lekérni készülünk, hogy potenciálisan jobb
#   hibaüzenetet készíthessünk.
# Utasításmódosító „if”-nek kell lennie, különben a „local” helyi lesz az
#   „if”-blokk hatóköréhez képest.
local $CurrentObject = $_[1] if !$CurrentObject;
                        
Használjon rövid sorvégi magyarázatokat a részletes információk hozzáadásához.

Ez lehet vagy teljes mondat (nagy kezdőbetű és központozás), vagy csak egy kifejezés (kis kezdőbetű és nincs központozás).

$BuildMode = oct $Param{Mode};   # oktális *típusról*, nem oktális *típusra*

# vagy

$BuildMode = oct $Param{Mode};   # Átalakítás oktális *típusról*, nem oktális *típusra*.

                        

Adatbázis kölcsönhatás

SQL-utasítások deklarációja

Ha nincs esély az SQL-utasítás megváltoztatására, akkor azt a Prepare függvényben kell használni. Ennek az az oka, hogy az SQL-utasítás és a kötési paraméterek közelebb vannak egymáshoz.

Az SQL-utasítást egy összefűzések nélküli, pontosan behúzott szövegként kell megírni úgy, mint például ezt:

return if !$Self->{DBObject}->Prepare(
    SQL => '
        SELECT art.id
        FROM article art, article_sender_type ast
        WHERE art.ticket_id = ?
            AND art.article_sender_type_id = ast.id
            AND ast.name = ?
        ORDER BY art.id',
    Bind => [ \$Param{TicketID}, \$Param{SenderType} ],
);
                

Ezt könnyű olvasni és módosítani, és az üres karaktereket jól tudják kezelni a támogatott DBMS-ek. Az automatikusan előállított SQL-kódnál (mint a TicketSearch modulban) ez a behúzás nem szükséges.

Visszatérés hibák esetén

Valahányszor adatbázis-függvényeket használ, kezelnie kell a hibákat. Ha valami elromlik, az visszakerül a szubrutinból:

return if !$Self->{DBObject}->Prepare( ... );
                

Korlát használata

Használja a Limit => 1 korlátozást, ha csak egyetlen sort vár visszatérésként.

$Self->{DBObject}->Prepare(
    SQL   => 'SELECT id FROM users WHERE username = ?',
    Bind  => [ \$Username ],
    Limit => 1,
);
                

A while ciklus használata

Mindig használja a while ciklust még akkor is, ha csak egyetlen sort vár visszatérésként, mivel néhány adatbázis nem szabadítja fel az utasításkezelőt, és ez furcsa hibákhoz vezethet.

JavaScript

Böngészőkezelés

Az összes JavaScript betöltődik minden böngészőben (nincsenek böngésző trükközések a sablonfájlokban). A kód felelős annak eldöntéséért, hogy ki kell hagynia vagy végre kell hajtania saját magának bizonyos részeit az egyes böngészőkben.

Könyvtárszerkezet

Könyvtárszerkezet a js/ mappán belül:

* js
    * thirdparty              # harmadik féltől származó függvénykönyvtárak,
        * ckeditor-3.0.1      #   amelyek mindig tartalmaznak verziószámot a
        * jquery-1.3.2        #   könyvtáron belül
    * Core.Agent.*            # az ügyintézői felületre jellemző dolgok
    * Core.Customer.*         # ügyfélfelület
    * Core.*                  # közös API
            

Harmadik féltől származó kód

Minden harmadik féltől származó modul saját alkönyvtárat kap: „modulnév”-„verziószám” (például ckeditor-3.0.1, jquery-1.3.2). Ezen belül a fájlneveknek nem kell verziószámot vagy előtagot tartalmaznia (hibás: jquery/jquery-1.4.3.min.js, helyes: jquery-1.4.3/jquery.js).

Változók

  • A változóneveket CamelCase jelölésrendszerben kell írni, akárcsak a Perlben.

  • A jQuery objektumot tartalmazó változókat $ karakterrel kell kezdeni, például: $Tooltip.

Függvények

  • A függvényneveket CamelCase jelölésrendszerben kell írni, akárcsak a Perlben.

Névterek

  • Ez a rész még nincs megírva…

Kódmagyarázatok

A Perl-kód magyarázási irányelvei a JavaScriptre is vonatkoznak.

  • Egysoros megjegyzéseket // karakterekkel kell készíteni.

  • Hosszabb megjegyzéseket /* ... */ karakterekkel kell készíteni.

  • Ha megjegyzésre állítja a JavaScript kód egyes részeit, akkor csak a // karaktereket használja, ugyanis a /* ... */ használata problémákat okozhat a reguláris kifejezéseknél a kódban.

Eseménykezelés

  • Mindig a $.bind() függvényt használja a jQuery rövidített nevű eseménymetódusai helyett a jobb olvashatóságért (hibás: $SomeObject.click(...), helyes: $SomeObject.bind('click', ...).

  • Ne használja a $.live() függvényt! Súlyos teljesítményproblémáink voltak a $.live() függvénnyel az egéreseményekkel összefüggésben. Ne használja, amíg nem ellenőrizhető, hogy a $.live() problémák nélkül működik a többi eseménytípussal.

  • Ha eseményeket köt a $.bind() függvénnyel, akkor győződjön meg arról, hogy korábban leválasztotta azokat az $.unbind() használatával annak biztosításához, hogy az események ne legyenek kétszer kötve, ne kelljen a kódot még egy alkalommal végrehajtani.

CSS

  • A legkisebb felbontás 1024×768 képpont.

  • Az elrendezés folyékony, amely azt jelenti, hogy ha a képernyő szélesebb, akkor a helyet fel fogja használni.

  • Az abszolút méretmeghatározásokat képpontban (px) kell megadni, hogy következetes kinézetet kapjon a legtöbb platformon és böngészőben.

  • A dokumentáció CSSDOC használatával készül (nézze meg a CSS-fájlokat példaként). Az összes logikai blokknak rendelkeznie kell egy CSSDOC megjegyzéssel.

Szerkezet

  • Az objektumorientált CSS megközelítést követjük. Lényegében ez azt jelenti, hogy az elrendezés különböző általános építőkockák egyesítésével érhető el egy bizonyos látványterv megvalósításához.

  • Ahol csak lehetséges, nem szabad a modulra jellemző látványtervet használni. Például ezért nem dolgozunk azonosítókkal a body elemen sem, ha az elkerülhető.

Stílus

  • Az összes meghatározásnak ugyanabban a sorában van a { karakter mint a kiválasztó, az összes szabály szabályonként egy sorban van meghatározva, a meghatározások egyetlen } karaktert tartalmazó sorral végződnek. Nézze meg a következő példát:

    #Selector {
        width: 10px;
        height: 20px;
        padding: 4px;
    }
                        

  • A : és szabály értéke között van egy szóköz.

  • Minden szabály 4 szóközzel van behúzva.

  • Ha több kiválasztó van megadva, akkor vesszővel válassza el azokat, és mindegyiket tegye külön sorba:

    #Selector1,
    #Selector2,
    #Selector3 {
        width: 10px;
    }
                        

  • Ha a szabályok egyesíthetők, akkor egyesítse azokat (például egyesítse a background-position, background-image, stb. szabályokat a background szabályba).

  • A szabályoknak logikai sorrendben kell lenniük egy meghatározáson belül (az összes színre jellemző szabály együtt, az összes pozicionáló szabály együtt, stb.).

  • Az összes azonosító és név CamelCase jelölésrendszerben van írva:

    <div class="NavigationBar" id="AdminMenu"></div>