Да разгледаме този код:
describe Registration do
it "disallows duplicates" do
create(:registration, uid: '123', provider: 'twitter')
first_registration = build(:registration, provider: 'twitter', uid: '123')
second_registration = build(:registration, provider: 'twitter', uid: '234')
third_registration = build(:registration, provider: 'facebook', uid: '123')
first_registration.should_not be_valid
second_registration.should be_valid
third_registration.should be_valid
end
end
Трите променливи, first_registration
, second_registration
, third_registration
, са подравнени по =
, а виканията на функции отдясно са подравнени по запетайки. Предимствата, които виждам в това са:
-
Отляво лесно може да се сканират имената на променливите. Ако тялото на кода, което използва тези променливи, е по-сложно, лесно може да се "индексира" визуално -- гледаш в лявата страна променливата, която в момента те интересува и лесно виждаш отдясно какво има. Аз лично много рядко чета дефиниции на променливи като проза -- ляво -> дясно. По-скоро ги сканирам набързо и после докато чета употребата им, се консултирам с "индекса".
-
Отдясно имаме някакви доста хомогенни извиквания на функцията
build
. Разликите между извикванията са това, което ни интересува и когато са подравнени, е лесно да се видят с един поглед.
Това може да не е твърде очевидно в кратко парче код, но особено при по-големи буци текст става все по-полезно. Може да се спори, че не трябва да се стига до големи буци код, но зависи от случая. Примерно,
$icon-arrow-thick-right: "\e600";
$icon-arrow-thick-left: "\e601";
$icon-arrow-thick-up: "\e602";
$icon-arrow-thick-down: "\e603";
$icon-arrow-thick-b-right: "\e604";
$icon-arrow-thick-b-up: "\e605";
$icon-arrow-thick-b-left: "\e606";
$icon-arrow-thick-b-down: "\e607";
$icon-arrow-thin-right: "\e608";
$icon-arrow-thin-up: "\e609";
$icon-arrow-thin-left: "\e60a";
И така още 400 реда. Сравни със:
$icon-arrow-thick-right: "\e600";
$icon-arrow-thick-left: "\e601";
$icon-arrow-thick-up: "\e602";
$icon-arrow-thick-down: "\e603";
$icon-arrow-thick-b-right: "\e604";
$icon-arrow-thick-b-up: "\e605";
$icon-arrow-thick-b-left: "\e606";
$icon-arrow-thick-b-down: "\e607";
$icon-arrow-thin-right: "\e608";
$icon-arrow-thin-up: "\e609";
$icon-arrow-thin-left: "\e60a";
Това не е съвсем код, а по-скоро table of contents, и като такава, е супер полезно да е подравнена. Само си представи книга, в която съдържанието е описано неподравнено и колко досадно би било да се ориентираш по страници/глави. Отново, отляво имаш списък, който лесно се сканира, отдясно имаш доста хомогенно съдържание, в което лесно се виждат разликите от ред до ред (и съответно също лесно се сканира).
Стефан спомена CSS. Всъщност, той ме убеди да не подравнявам CSS и мисля, че има право. Работата е там, че тези две правила не са много силно изявени. Рядко искаш да сканираш "етикетите", примерно това, че един CSS селектор използва "margin" и "padding" не е толкова важно, колкото какви са им стойностите. А от дясната страна често имаш доста различни стойности -- пиксели, двойки числа, четворки числа, текст. Силно нехомогенно съдържание и съответно като че ли безсмислено да се подрежда. Има някои изключения, примерно:
dl {
-webkit-margin-before: 4px;
-webkit-margin-after: 4px;
margin-before: 4px;
margin-after: 4px;
}
Но пък от друга страна, това е трудно да се поддържа подравнено по автоматичен начин. Ако е в някакъв mixin може би бих го направил, просто защото няма да се докосва често.
Такъв код донякъде по-трудно се редактира. Трябва да имаш нещо в редактора, което да ти помага, и мисля, че доста хора нямат и си ги подравняват ръчно. Това не е много умно. Според мен не си заслужава толкова да се хаби време, ако редактора ти няма tooling за целта. Плюс това може да имаш проблеми с git diff, че на всяка промяна с подравняване, ще си "докоснал" целия параграф. Макар че днес четох за -b
флага (https://coderwall.com/p/crj69a), който просто игнорира whitespace промени. Което ми звучи като напълно очевидно решение.
Друг проблем може да са големите разлики в дължините. Примерно:
one = 1
two = 2
three = 3
forty_two_hundred_and_twenty = 4220
Вече става по-трудно да направиш връзката между "one" и "1", защото са доста далече. Решението ми в такива случаи е просто:
one = 1
two = 2
three = 3
forty_two_hundred_and_twenty = 4220
thirty_five_thousand = 35_000
Може да се запиташ и защо някои променливи от кода ти са по една дума, а други -- цяла фраза. Напоследък се замислям, че такава инконсистентност прави кода по-трудно четим. Не знам какво може да се направи по въпроса.
Относно search-and-replace, не виждам проблем. Във вим вместо foobar =
ще е foobar\s\+=
. И дори и така не бих го направил автоматично, а с възможност за manual intervention.
Зависи. В случаи с много данни и то еднородни такива, със сигурност бих искал да са подравнени. Мисли си за горния пример с SCSS променливите или примерно за schema на база данни. В случаи с тестове, където често имаш setup фаза с няколко извиквания на еднородни функции с различни параметри, също. Оттам нататък не ми е толкова ясно кога е полезно и кога не толкова, но бих казал, че ако ще се прави, по-добре да се прави някакъв effort за това навсякъде. Правило като "можеш да го правиш ако решиш, че ще помогне" ми изглежда безсмислено, понеже изисква активна мисъл при всяка промяна "има ли нужда от подравняване или не".
Като цяло, бих казал, че е решение на екипа -- или подравняваш консистентно, или не. И двете са ок, и с двете се преживява.
Имай предвид освен това, че доста от "аргументите" тук са reverse justification. На мен ми изглежда по-четимо, затова се опитвам да разбера защо. Възможно е ако спра да подравнявам примерно 2 години, да намразя подравняването, знам ли. Но като цяло ми изглежда смислено в много случаи.