Относно конвенциите

Хвърлете един поглед на това. Кратка статийка, която навлиза в детайли за стандартите за писане на код. Това е тема, над която съм размишлявал доста време и имам някои фашистки разбирания. Връзката ми дава страхотен повод да споделя някои впечатления.

Във всеки един проект в който работя се опитвам с драконови мерки да налагам железни стандарти за спазваната конвенция. Причината е, че съм много чувствителен към неконсистенции в кода. Винаги подреждам всичко по един и същи начин (празни редове, скоби, пренасяне на аргументи при дълъг ред и т.н.), използвам една и съща част от стандартната библиотека и следвам една схема за наименуване на нещата. Всякакви отклонения ми се набиват на очи и очаквам да има някаква причина за тях. Например, като видя някъде ArrayList заключавам, че кода прави здраво индексации и линейното обхождане ще е неефективно. Като видя някъде while вместо for за Iterable, очаквам да има някакъв по-сложен алгоритъм от едно “за всеки”. А когато видя for вместо .each в Ruby очаквам индексната променлива да се използва някъде по-надолу. Съответно, всеки път когато конвенцията е нарушена без причина това само ми отвлича вниманието и ми губи времето.

Вариациите в езика, бил той компютърен или естествен, са начин за изразяване. “Студено ми е.” и “Умирам от студ!” носят една и съща информация (очевидно температурата е кофти), но звучат различно - първото е в тона на хладно твърдение (pun not intended), докато второто изразява по-силна емоция. Езиците за програмиране имат същите нюанси, макар и не толкова изявени. Както не слагате слагате акценти и емоция в речта си когато ви скимне, така и не бива хаотично да ползвате изразните вариации в езика. Щом можете да правите нещата по повече от един начин, правете ги по повече начини консистентно. Разликите в стила и подхода са носител на информация, не пособ за себеизразяване - for(;;) казва, че обхождате някаква колекция, докато while - че се опитвате да достигнете някакво условие. Те не са начин да илюстрирате естетическите вкусове на потиснатия артист в себе си.

Това важи с още по-голяма сила когато работите в екип. Ако сте от онези хора, които вярват, че “различията в стила трябва да се толерират, понеже така бързо може да видите кой е писал кода” заслужавате да ви застрелят (малко след като ви обяснят какво е version control). В идеалния случай не трябва да има никакъв начин да разберете кой какво е писал само четейки кода. Стиловите нюанси (различно форматиране, различна схема на наименуване, различен подход за стандартни неща или не дай си боже екзотични перверзии) само създават шум и затормозяват прочита. Бъдете добри дружки и правете нещата консистентно - в дългосрочния план всички ще се чувствате много по-добре.

Като цяло, стила носи информация. А най-лошото, което може да направите с информацията, е да я лишите от смисъл.

4 Comments

  1. Posted November 14, 2007 at 9:25 am | Permalink

    Според мен използването на определени езикове конструкции (for vs. while, ArrayList vs. LinkedList), е твърде ниско ниво за да подлежи на конвенция - програмиста трябва да използва целия арсенал на езика си за да се изрази четливо и еднозначно.

    От досегашната ми работа мога да направя няколко извода за конвенциите.

  2. Posted November 14, 2007 at 10:25 am | Permalink

    Пак мислим еднакво с тебе ;)

  3. Posted November 14, 2007 at 11:55 am | Permalink

    @Свилен:
    Сега, аз пък точно за това адвокатствам - че ArrayList/LinkedList, for/while са вариация на едно израно средство - позволяват ти да кажеш едно нещо по няколко начина. И е особено критично да се ползват консистентно в кода. А нещо което е консистентно като нищо може да подлежи на конвенция, била тя и полу-формален фолклор в екипа, а не драконов закон.

    Ще ти дам по-конкретен пример.

    for (int i = 0; i < numbers.length; i++) {
      System.out.println(numbers[i]);
    }
    

    Проста програма. Чете се като “за всяко число в numbers, изведи го на екрана”. Виж какво става, ако го напишеш с while:

    int i = 0;
    while (i < numbers.length) {
        System.out.println(numbers[i]);
        i++;
    }
    

    Действието е идентично. Дори ще генерира същия байт-код. Но се чете така “докато i е по-малко от дължината на numbers, извеждай i-тото число в numbers и увеличи i след това”. Което е много по-далеч от идеята на кода (intention).

    Когато човек използва for/while неподходящо, само дава грешни сигнали. Не изразява кода четливо и еднозначно, в твои думи. Когато избира между ArrayList и LinkedList ползвайки rand(), вместо да прецени кое е по-подходящо създава объркване.

    Това важи още повече за някои неща които са по средата. Класическата конвенция в ruby е да се ползва begin/end за блоково на повече от един ред и { } за блокове на един ред. Алтернативната идея е да се ползва begin/end когато важното са странични ефекти, докато { ... } като се изчислява резултат. Която идея да изберете, трябва да сте консистентни в рамките на екипа - иначе твоя код ще ме обърква, докато моя код ще те дразни, защото ползвам { ... } за големи блокове.

  4. Posted November 14, 2007 at 1:32 pm | Permalink

    Признавам - ArrayList/LinkedList не добър пример - все пак това са различни фундаментални типове данни с характерните си свойства; прилагането им трябва да бъде съобразено.

    От друга страна, според мен влагането на нюанси в for/while и описвайки ги в конвенция, е малко пресилено. Преполагам никой от нас не използва while за да извърти един масив - просто защото е свикнал да гледа, че това се прави с for - в учебниците, в кода на колегите, в чужд софтуер. Съгласен съм, че for each конструкциите са още по експресивни. Колкото повече “стандартни конструкции” един програмист използва, толкова по-лесен е кода за четене - но пак искам да уточня: ако програмиста смята, че дадена конструкция отговаря по-добре на намерението му - нека я ползва; не трябва конвенцията да го спира. Добър пример е дебата около goto - в език като C, където програмните изключенията (exceptions) са недостъпен лукс. Например функцията с goto, което прехвърлят изпълнението в края при невалиден входни параметри е доста по-четима от няколко вложени if-a. Ето тук конвенция “goto e враг номер едно на Тутраканската селищна система” би спънал четливия код.

    Мойте 5 ст’инки.

One Trackback

  1. By Codito ergo sum » Думи от занаята on January 25, 2008 at 11:40 am

    […] са важни. Трябва да внимаваме с употребата им за да можем да се разбираме. Но често не стигат, когато говорим за някаква […]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*