summaryrefslogtreecommitdiff
path: root/content/posts/2025-04-05-tabs-or-spaces.md
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--content/posts/2025-04-05-tabs-or-spaces.md400
1 files changed, 400 insertions, 0 deletions
diff --git a/content/posts/2025-04-05-tabs-or-spaces.md b/content/posts/2025-04-05-tabs-or-spaces.md
new file mode 100644
index 0000000..a44e052
--- /dev/null
+++ b/content/posts/2025-04-05-tabs-or-spaces.md
@@ -0,0 +1,400 @@
+---
+categories:
+- Размышления
+date: '2025-04-05T16:53:27+03:00'
+description: null
+image: null
+location: Казань
+tags:
+- размышления
+title: Табы или пробелы?
+---
+
+Так получилось, что с Нового Года я ничего в блог не писал. Тому причина в
+личной загруженности, и в не менее личной лени. Так же я делал некоторые
+эксперименты над самим блогом, потому что моё внутреннее чувство прекрасного не
+даёт мне просто остановиться и не трогать то, что работает.
+
+Но всё же, я чувствую внутреннюю потребность написать небольшую заметку с
+размышлениями, которые недавно приходили ко мне в голову.
+
+А связаны они с тем, что есть определённые догмы в индустрии, которые непонятно
+(ну или понятно) почему появились, и которым слепо следуют, хотя, как будто они
+уже не имеют смысла.
+
+<!--more-->
+
+## Вечный спор
+
+Для затравки, «вечный спор» табы или пробелы использовать в коде для отсутпов.
+Лично для меня здесь не то что выбор очевиден, для меня очевидно, что и самого
+выбора то нет. Конечно же, только табы! Отступ пробелами просто не имеет права
+на жизнь, и вот почему:
+
+* Во-первых, это просто какой-то костыль, использовать пробел не по назначению.
+ Наверное, не очень очевидно, но назначение пробела — это именно разделение
+ слов. Невероятно! А наначение таба — как раз таки форматирование отступа.
+ Давайте использовать инструменты по назначению!
+* Во-вторых, и самое главное, как по мне, это гибкость табуляции. Я, как
+ читающий код, волен сам выбирать размер отступа. Например, если у меня узкий
+ экран (смартфон, например) — я выберу отступ в 2 *визуальных* пробела.
+ Наоборот, если бы у меня было слабое зрение — я бы выбрал отступ в бо́льшее
+ число *визуальных* пробелов.
+* В-третьих, исходя из предыдущего пункта, я считаю, что использование именно
+ пробелов — это диктование автором исходника мне своей воли в виде своих
+ предпочтений (например, только 4 пробела, и никак иначе!). А какого чёрта? Это
+ буквально насилие! Зачем? Я считаю, это не допустимо. Пусть у каждого будет
+ возможность выбирать себе настройки отображения на *своей* машине под *свои*
+ вкусы, а не вкусы автора!
+* В-четвёртых, самое малозначительное — это то, что таб это 1 байт, а пробелов
+ обычно больше чем 1 байт (от 2 до 8). Я считаю этот аргумент малозначительным,
+ т.к. уж что что, а места на носителях информации нынче в достатке. Но тем не
+ менее, это один из аргументов!
+
+А что по аргументам за пробелы? Да нет их. Ну окей, предположим, что есть. Во
+многих кодстайлах (PEP-8, PSR итп) закреплены именно пробелы. Я не понимаю,
+почему, вроде как, умные люди которые эти стандарты придумывали так сделали.
+Возможно, привычка. Но является ли привычка каких-то людей аргументом? Наверное,
+нет. И самое грустное, что эти стандарты уже не поменять, ибо с их
+использованием *уже* написаны мегатонны кодов.
+
+Единственное, меня радует, что хотя бы в стандарте форматирования моего любимого
+языка Go этой откровенной чуши нет. В Go отступы приняты табами и только ими.
+
+Сразу скажу, я говорил только про отступы в начале строки, но не про отступы
+внутри строки, например, чтобы выстраивать значения подряд идущих констант в
+одну ровную колонку. Там, вроде как, пробелы вполне оправданы. Но это не точно.
+Я пока не решил для себя.
+
+Думаю, здесь насчёт табов и пробелов можно завершить. Если есть что накинуть —
+пишите письма, e-mail внизу страницы.
+
+## Вечный консенсус
+
+Про табы и пробелы была скорее затравочка. Там, как мне кажется, всё очевидно.
+Но есть менее очевидная, но как мне кажется очень родственная тема. Эта тема
+вызывает сильно меньше споров, т.к. вроде как в ней уже есть консенсус. Но этот
+консенсус ошибочен!
+
+А говорю я про форматирование длины строк! А именно, т.н. hard-wraps и
+soft-wraps. Если коротко, при hard-wraps в текст в точках переноса (например, на
+80 или 120 колонке) вставляются символ переноса строк (`\n`), при мягком
+переносе текст остается на одной строке, но выглядит так, как будто он разделен
+на несколько строк.
+
+А начну я с небольшой предыстории, как я к этому пришёл. Как я уже писал в
+начале, у меня есть постоянное шило в седалище, которое не даёт мне просто
+остановиться и использовать то, что работает, как минимум, в контексте этого
+блога. И из последнего куда я смотрел — протокол Gemini[1]. Разбирая его, меня
+сначала немного удивила его особенность, а именно:
+
+=> https://geminiprotocol.net/ [1]
+
+> Text in Gemtext documents is written using "long lines", i.e. you (or your
+> editor) shouldn't be inserting newline characters every 80 characters or so.
+> Instead, leave it up to the receiving Gemini client to wrap your lines to fit
+> the device's screen size and the user's preference. This way Gemtext content
+> looks good and is easy to read on desktop monitors, laptop screens, tablets
+> and smartphones.
+
+> Note that while Gemini clients will break up lines of text which are longer
+> than the user's screen, they will not join up lines which are shorter than the
+> user's screen, like would happen in Markdown, HTML or LaTeX. This means that,
+> e.g. "dot point" lists or poems with deliberately short lines will be
+> displayed correctly without the author having to do any extra work or the
+> client having to be any smarter in order to recognise and handle that kind of
+> content correctly.
+
+Сначала, я подумал, да это же нифига не удобно, что используются длинные строки,
+а не склеиваются разделённые одним переносом как в Markdown! Более того, это моё
+возмущение подогревалось тем, что я всё это время был сторонником как раз
+hard-wraps и форматировал что код, что markdown для блога по 80 или 120 колонке.
+Потому что так всегда и везде было принято. Но потом вчитавшись, я понял, что
+как раз таки «склеивание» Markdown это максимально неправильное поведение! Оно
+порождает такие минусы, как более сложный парсинг, который должен обрабатывать
+по разному один и два переноса строк, неочевидность, когда пишешь текст в
+редакторе, а отображается он совсем по другому, потенциальные ошибки, когда
+абзацы внезапно склеиваются, и т.п.
+
+При этом, парсинг Gemtext поразительно простой. В общем случае, достаточно
+парсить по строке, и не думать о предыдущем состоянии (относится текущая строка
+к предыдущему параграфу или таки нет). Единственное исключение —
+преформатированный текст, при парсинге которого надо помнить состояние. Но и это
+очень просто, достаточно держать единственный флаг который говорит, мы сейчас в
+нормальном состоянии или в состоянии преформатированного текста. И переключать
+этот флаг когда очередная строка начинается с *```*. Вообще, Gemtext кажется
+наиболее правильным и приятным для меня языком разметки. Наверное, я на него
+перейду. Но потом, сейчас нет времени.
+
+К чему я тут углубился в описание формата Gemtext? А вот к чему: только после
+прочтения спеки этого формата до меня сошло озарение, что использование длинных,
+а не обрезанных по 80 или 120 или ещё какую колонку более правильное не только
+для формата разметки, но и для обычного кода!
+
+И вот аргументы:
+
+* Во-первых, все редакторы кода поддерживают soft-wrap и каждый волен выставить
+ для своего личного редактора удобную ему длину строки, а не подчиняться
+ привычкам автора кода.
+* Во-вторых, за длину в 80 символов топят в основном старпёры что-то там
+ говорящие про терминалы шириной в 80 символов. Только и этот аргумент не
+ понятен. Когда вы в последнее время видели терминал в 80 символов? Не эмулятор
+ терминала, а именно сам терминал? Ну даже, хорошо, пусть будет этот терминал в
+ 80 символов. Но он что, не умеет переносить? Подозреваю, что может. И в чём
+ тогда проблема? Непонятно. Короче, требование в 80 символов (ну или более
+ современное в 120) выглядит как высосанное из пальца, потому что под ним нет
+ реальной основы кроме каких-то там исторических причин на доисторическом
+ железе.
+* В-третьих, см. пункт про насилие автора кода над читателем кода. Например,
+ опять таки, узкий монитор например. И на нём не soft-wrapped текст может
+ вызывать горизонтальную прокрутку. И это убого.
+* В-четвёртых, да, это усложняет парсинг. Это слабый аргумент, я знаю. Как
+ пример, правильный парсер Markdown (не буду тут бомбить про количество разных
+ стандартов Markdown) пишется не то чтобы очень просто. В это же время,
+ написать парсер Gemtext который полностью покроет спецификацию — дело максимум
+ часа-двух для любого, кто программирует больше, хотя бы, нескольких месяцев!
+
+В общем, как и в случае с табо-пробелами я не вижу ни одной достойной причины
+делать жесткие переносы строк по какой-то длине!
+
+Возможно, я что-то упустил — тоже можно по этому поводу поспорить со мной в
+электропочте. Возможно, я даже поменяю мнение, но наврядли.
+
+## Update 06.04.25
+
+Как я и просил, один хороший человек, Владислав
+(https://t.me/c/1331521959/2285), написал ответ. Прокомментирую его здесь:
+
+> Мне есть что сказать про ширину таба и 80 символов.
+
+> Аргумент про разную ширину таба работает слабо: многие стили предполагают его
+> фиксированную длину. Если ставить другой, то форматирование ломается.
+
+> Пример: ядро Linux, где ширина таба 8, и аргументы функций "плывут" при другой
+> ширине.
+
+Я не единожды видел этот аргумент, но он как раз и кажется мне слабым. Большая
+ли разница для читающего код, как именно он его видит:
+
+```
+// tabsize=2
+ func someFunc(
+ one,
+ two,
+ three,
+ )
+...
+ callOfSomeFunc = someFunc(
+ "one",
+ "two",
+ "three",
+ )
+```
+
+или так
+
+```
+// tabsize=4
+ func someFunc(
+ one,
+ two,
+ three,
+ )
+...
+ callOfSomeFunc = someFunc(
+ "one",
+ "two",
+ "three",
+ )
+```
+
+или даже так
+
+```
+// tabsize=8
+ func someFunc(
+ one,
+ two,
+ three,
+ )
+...
+ callOfSomeFunc = someFunc(
+ "one",
+ "two",
+ "three",
+ )
+```
+
+Кажется, что для 8 пробелов на таб всё сильно уезжает, но раз человек себе так
+настроил — то как будто его право и наверное были основания?
+
+
+> Про 80 символов. Дело вообще не в размере терминала или ширине перфокарты.
+> Некоторые программисты разделяют редактор на две вкладки, чтобы смотреть два
+> файла.
+
+И тогда soft-wrap как раз и вместит весь код в каждую из половинок без
+горизонтальной прокрутки, о чём я и говорю.
+
+> Некоторые используют большой шрифт. С шириной в 120 символов мы лишаем из
+> возможности удобно читать код. К тому же, я считаю этот аргумент важным, 120
+> символов - это способ замаскировать плохой код. Чувак сделал 5 уровней
+> вложенности в коде? Отлично! Главное чтобы в 120 символов влезло.
+
+Всё так! Возможно, я не очень подробно расписал, но основная моя мысль в том,
+что такое жесткое ограничение мне кажется просто надуманным и взятым с потолка.
+А если я после функции хочу написать небольшой коммент и он ну никак не влезает
+на пяток символов? Новую строку ради этого делать? Ну как-то бредово. А для
+указанного случая гораздо лучше бы звучало ограничение в стандарте типа «не
+используйте больше 3 уровней вложенности в коде». Это хотя бы имело вполне себе
+обоснование, то что скорее всего такой код просто архитектурно неверен и его
+стоит пересмотреть.
+
+> Конечно, можно сказать что есть длинные константы или имена функций, но этот
+> спор становится менее однозначным. Как по мне вполне хороший консенсус - это
+> 100 символов в строке
+
+Здесь не согласен. Здесь опять «магическая константа» с потолка.
+
+> В целом, эти срачи мне кажутся достаточно поверхностными. Они в своем корне
+> несут вопрос "как повысить читаемость кода?", но акцентируются на мелочах.
+
+Согласен. Мелочи. Но почему и бы про мелочи не поговорить :) Из них по
+отдельности всё и строится (избитая фраза, да). В больших стандартах обычно
+говорится просто декларативно «только пробелы, отступ 4 пробела, длина строк
+120» и всё. А зачем и почему — опускается, как будто всем всё и так понятно. Мне
+вот не очень. Чувствую себя ребёнком спрашивающим «Почему небо синее?». Потому
+что мне кажется, что под этим требованием нет объективного требования кроме «так
+принято». А «так принято» я часто и принимаю как валидный аргумент, например,
+когда прихожу в какой-то проект, но в сути своей аргументом не является.
+
+> Хотелось бы иметь какие-то объективные метрики, какая-то работа в этом
+> направлении была проделана, но, как я понял, это, во-первых, недостаточно
+> точные метрики, а во-вторых, недостаточно развитая история.
+> https://seeinglogic.com/posts/visual-readability-patterns/
+
+Интересная статья, спасибо, с удовольствием прочитал. В целом, по выводам
+(https://seeinglogic.com/posts/visual-readability-patterns/#8-patterns-for-improving-code-readability)
+согласен. Метрика по Хольстеду (или как это перевести?) выглядит интересно, тем
+что она чётко считается (хотя когда я руками считал, что-то у меня не сошлось с
+примером :) ).
+
+Из объективных метрик, тут вскользь ещё упоминалась цикломатическая сложность,
+которая вполне себе имеет право на жизнь.
+
+А так же, только что пришло в голову что можно читабельность кода оценивать как
+вторую (?) производную от отступов по непустым строкам. При этом, чем эта
+производная ближе к нулю — тем лучше.
+
+То есть, грубо говоря вот такой «код»:
+
+```
+_____
+ ________
+ _____
+ _______
+ ___
+ ___
+ _____
+ __
+ ____
+___
+```
+
+Лучше чем, такой:
+
+```
+_____
+ ________
+ _____
+ _______
+ ___
+ ___
+ _____
+ __
+ ____
+ ___
+```
+
+Это стоит ещё подумать, это буквально пришло в голову только что, пока читал
+статью.
+
+P.S.: Из забавного
+
+> As others have written, computers are fast and premature optimization is a bad
+> thing.
+
+Сначала они пишут «computers are fast» а потом происходит такое: [2]
+
+=> https://tonsky.me/blog/disenchantment/ru/ [2]
+
+
+## Update 06.04.25 - 2
+
+Со вчерашнего дня я решил дополнить немного ещё.
+
+Во-первых, хочу немного снизить градус холиворности и радикальности. Ещё раз
+упомяну что не вижу проблем для выравнивания пробелами текста внутри строки. То
+есть например, вот так:
+
+```
+→ → ConstWithLongName = 0
+→ → Const1 = 1
+→ → Const2 = 2
+→ → Const3 = 3
+```
+
+для меня вполне нормально кажется. Даже более того, табы *внутри* строки кажутся
+плохим решением. Я говорю только про отступы в начале строки.
+
+Во-вторых, насчёт длинных строк. Я расписал немного сумбурно и в одну кашу
+смешал как код, так и просто текст. Не стоило так. Хоть это и разные сущности,
+но я всё равно считаю жесткое ограничение необоснованным ни там ни там. Но по
+разным причинам:
+
+* Для обычного текста ограничение в N символов выглядит таким же не обоснованым,
+ как, например, требование автора «Читайте мои тексты только шрифтом Arial
+ 12pt». Глупость? Глупость.
+* Так же встречал, что люди используют это ограничение при написании электронных
+ писем. Это выглядит как минимум странно. Письмо пишется для кого? Для
+ получателя, т.е. читателя. Почему отправитель за читателя решает то, как у
+ него будет отображаться письмо? Я часто читаю почту со смартфона с узким
+ экраном, но средним шрифтом (чтобы меньше напрягать глаза). И горизонтальная
+ прокрутка выглядит не очень. Горизонтальная прокрутка вообще почти всегда
+ выглядит не очень и её стоит избегать всеми силами.
+* Для кода же история другая. Я не настолько поехал чтобы требовать всё писать в
+ одну строку. Если у функции в сигнатуре много (больше одного - двух)
+ аргументов — то это отличная идея написать их в столбик, а не в длинную линию,
+ которая ещё неизвестно как перенесётся. Я против именно переноса только из-за
+ магической константы колиечества символов.
+
+Да и вообще я ни от кого ничего не требовал. Я предлагаю только задуматься, а
+обоснованны ли «общепринятые» вещи? Может, уже прошло какое-то время и ситуация
+поменялась и удобнее и эффективнее выбрать что-то другое?
+
+И как будто стоит абстрактному «читателю», к которому я отсылал, в этом посте,
+решать этот вопрос техническими средствами, типа editorconfig + pre-commit хуки
+на форматирование в принятый в команде формат? Возможно да. Иначе получится, что
+борясь за личную свободу — нарушаешь чужую свободу <del>писать говнокод</del>.
+
+А .editorconfig я себе такой в home положил:
+
+```.editorconfig
+[*]
+indent_style = tab
+tab_width = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+soft_wrap = true
+
+[*.{yml,yaml}]
+indent_style = space
+indent_size = 2
+
+[*.json]
+indent_size = 2
+```
+
+Вроде как, покрывает основное.