Я натолкнулся на этот мануал в интернете, когда гуглил описание "Верблюжьей вёрстки". Меня, технически, очень продвинул данный текст, поэтому я взялся за его перевод, для себя. Переводчик я — так себе, моя основная цель — передать смысл текста в максимально полном объёме. Навык программиста и энтузиазм мне в помощь.
Текст написан от первого лица, и я решил сохранить этот момент. Поэтому "я" — это не я, а оригинальный автор статьи "Tao of Coding" — Коэн Уиттерс.
Читать далее
Данное руководство описывает стиль написания программного кода, который я разрабатывал несколько лет. Но стиль мой настолько неизвестен, что я не знаю никого, кто пользовался бы таким странным способом программировать, каким пользуюсь я. Тем не менее, он мне нравится и я бы хотел поделиться этим знанием (эй ты, везунчик, слышишь меня?). Этот стиль я использовал в разных языках: С, С++, Java, C#, Python,... .
Если вы хотите бегло ознакомиться со стилистикой написания, просто пролистайте страницу вниз и посмотрите на участки кода, написанные моим, "deWiTTERS" способом, и вы увидите, как удачно и красиво он выглядит.
Почему "стиль кодирования"?
Каждый программист использует какие-либо стилистические направления, для написания своих программ. Какие-то удачно, какие-то не очень. Стиль программирования добавляет коду единообразия, что может сделать алгоритм более понятным. Или более сложным. Есть, как минимум, две причины для применения стилей программирования:
разработка настолько читаемого и чистого кода, что любой, кто начнет разбираться в его дебрях, сделает это достаточно быстро. А ещё — это важно для тебя самого: тот случай, когда ты ковыряешь свой старый код, написанный год-два назад, и думаешь: "Блин, какого я тут понаписал, не могу вспомнить, что это всё значит..."
использование единообразного стиль написания кода любым программистом в команде, в которой ты будешь работать (или уже работаешь) — это большой, жирный плюс.
Поскольку большую часть кода я создаю самостоятельно — для меня нет необходимости заботиться по поводу причины номер два. А так как я безумно упрям, я не собираюсь использовать для работы чей-то другой стиль. Именно поэтому, мой стиль кодирования полностью оптимизирован для создания чистого, читаемого кода программы.
Основные правила
Я постарался объединить большинство аспектов своего стиля в следующих правилах.
Написанное должно быть абсолютно понятным настолько, насколько это вообще возможно.
Написанное должно быть легко читаемым настолько, насколько это возможно, кроме случаев, нарушающих первое правило.
Написанное должно быть простым настолько, насколько это возможно, кроме случаев, нарушающих первые два правила.
Говоря иначе: нужно писать код максимально просто, если, при этом, не страдают понятность кода и его читаемость. Или:
Всё нужно упрощать до тех пор, пока это возможно, но не более того.
Альберт Энштейн
И как профессиональный программист, вы просто обязаны следовать вышеописанным правилам, даже если вы не собираетесь следовать моему стилю кодирования.
Написание понятного и читаемого кода стало возможным с рождения современных языков программирования. Дни, когда программирование было связано лишь с ассемблером и двоичным кодом, давно прошли. Следовательно, мой стиль старается быть ближе к натуральному языку, насколько это возможно. Практически, вы можете проговаривать мой код, читая его как в книге. И кстати, скорее всего поэтому мой код плохо задокументирован. Я почти не оставляю комментариев! Я считаю комментирование кода плохим поведением (не в самом хорошем смысле этих слов), в принципе. Только когда я делаю что-то странное и непонятное, я добавляю комментарии, чтобы объяснить — зачем это надо. И я думаю, что комментированием не нужно объяснять, что делает ваш код. Код должен сам объяснять, что он делает.
И любой дурак может написать код, который будет понятен компьютеру. Хороший программист пишет код так, чтобы он был понятен человеку.
Мартин Фаулер.
Идентификаторы
Начнем со стиля самого востребованного раздела кодирования: идентификаторов. Любые идентификаторы, прочий код, комментарии — должны быть написаны на английском языке. Нормально, что разработанный проект мигрирует от одного программиста к другому, из компании в компанию, оказывается на другой стороне планеты. Ты не знаешь, где твой код окажется завтра — пиши всё на английском.
Переменные
Имена переменных необходимо писать в нижнем регистре, разделяя каждое слово в имени подчёркиванием. Подчёркивание очень похоже на натуральную запись языка и поэтому добавляет коду читаемости. Оно просто заменяет пробелы, как в обычных предложениях. Переменную "red_push_button", прочитать легче чем "RedPushButton", поверьте мне.
Если вы хотите, чтобы ваши переменные были максимально понятными, вы должны давать им очевидные, осмысленные имена. Естественно, что переменные представляют собой какой-то объект ("object") или значение ("value"), поэтому называйте их соответственно. Не тратьте время с переменными asflkwPrefixing slkfjjjfVariables fskjfeWith lskdTheir или kslfjType, потому что они непонятны — это бред какой-то. Если у вас есть переменная "age" (возраст), естественно и понятно, что это тип integer (целое) или unsigned short (короткое целое без знака). Если это "filename" (имя файла), что ж, скорее всего это string (строка). Думать не надо — всё просто! Иногда смысл переменной становится понятнее, если в её имя поместить тип, например для кнопки графического интерфейса: "play_button" или "cancel_button".
Существуют пре- и постфиксы, которые могут добавить читаемости вашим переменным. Вот список наиболее распространённых:
is_, has_. Используйте их в именах всех логических (boolean) переменных, и у вас никогда не будет проблем с пониманием типа этих переменных. И они будут отлично смотреться в выражениях условных переходов "if".
the_. Начинайте все глобальные переменные префиксом "the_", и всегда будет понятно, что она только одна такая.
_count. Используйте постфикс _count во всех переменных, которые представляют собой счетчики (количество элементов чего-либо). Используйте единственную форму "bullet_count" вместо множественной – "bullets" , так как множественной формой мы будем представлять массивы.
Массивы или другие переменные, представляющие списки должны указываться в множественной форме, как "enemies", "walls" или "weapons". Но не нужно делать так для всех типов массивов, так как некоторые из них реально не являются списками элементов. Например "char filename[64]" или "byte buffer[128]"
Const (или Final)
Константы или файналы должны быть написаны исключительно в ВЕРХНЕМ_РЕГИСТРЕ, словами с подчёркиванием в качестве разделителя, для их лучшей читаемости, например MAX_CHILDREN, X_PADDING или PI. Этот метод написания должен быть повсеместным для того, чтобы не путать константы с обычными переменными.
Можно использовать слова MAX и MIN в именах констант, чтобы представлять лимиты значений.
Типы
Типы — это целая классификация переменных. И это довольно абстрактный термин для того, чтобы описывать их используя классический английский язык. Но мы должны явно отделять типы друг от друга и от других идентификаторов. Именно для этого я использую ВерблюжийТипРаспиновкиСлов. Для каждого класса, структуры или перечисления (enum), и им подобные типы объявлений — используйте ВерблюжийРегистр.
Таким же образом вы можете использовать такой тип описания для стандартных, встроенных переменных. Ну например:
HelpWindow help_window;
FileHeader file_header;
Weapon weapons[ MAX_WEAPONS ];
Текст программы
if, else if, else
Есть несколько способов описания условия if. Начнем со скобок. Есть три вида помещения скобок за объявлением if
if(condition)
if (condition)
if( condition )
Я никогда не видел в тексте на английском языке, чтобы скобки размещались так, как в первом примере. Так почему мы должны использовать этот вариант в написании кода? Слова просто неправильно разделены между собой. Во втором примере, скобки с условием ставятся вместо оператора if (или отчуждаются от оператора), в то время как выражение в скобках является частью оператора if, а не самим оператором, поэтому последний пример является лучшим в описании. А также, последний пример является преимущественным, лучше предоставляя для обозрения содержимое в скобках.
if (!((age > 12) && (age < 18)))
if( !((age > 12) && (age < 18)) )
Лично я бы написал показанный код по другому, но здесь я хочу лишь показать вам пример.
А что насчет фигурных скобок? Может быть не использовать их?! Но к сожалению C, C++, Java или C# не позволят нам этого сделать. Только Python. Поэтому мы не сможем их проигнорировать, но мы можем поставить их так, чтобы они выглядели как в программах на Python — просто и чисто:
if( condition ) {
statements;
}
else if( condition ) {
statements;
}
else {
statements;
}
Когда условие очень длинное, нужно разбить его на строки. Попробуйте разбить его перед оператором и там, где условие менее всего связано. Расположите следующую линию с предыдущей, использовав отступ, чтобы раскрыть вложенность структуры. Не ставьте фигурную скобку справа, следом за условием, в данном случае, лучше поместить её на следующей строке, чтобы оставить последнюю часть условия чистым.
if( (current_mayor_version < MIN_MAYOR_VERSION)
|| (current_mayor_version == MIN_MAYOR_VERSION
&& current_minor_version < MIN_MINOR_VERSION) )
{
update();
}
Там, где есть только одно выражение, в теле условия, после объявления if, вы можете опустить фигурные скобки, и убедитесь, что поместили это выражение на следующей строке, но только если это не return или break, которые лучше написать в одну строку.
if( bullet_count == 0 )
reload();
if( a < 0 ) return;
while
Цикл while пишется точно так же, как и условие if. Для отступов я использую 4 пробела.
while( condition ) {
statements;
}
Для цикла do-while поместите часть while на той же строке, где располагается закрывающая выражение фигурная скобка. Таким образом достигается порядок, независимо от того, что это за while — конец или начало подблока.
do {
statements;
} while( condition )
for
Цикл for — единственная цель в жизни оператора — итерация цикла. Это именно то, что и делает этот оператор. Да, цикл for может быть безболезненно заменён циклом while, но лучше так не делать. Когда вам нужно повторить некоторое количество операторов — используйте for, а только если это реально невозможно, пользуйтесь while. Структура for проста и прекрасна:
for( int i = 0; i < MAX_ELEMENTS; i++ ) {
statements;
}
Bспользуйте литеры i, j, k, l, m для перебора чисел, а для перебора объектов используйте 'it'.
switch (case)
Оператор switch имеет схожую с if и while структуру. Единственная вещь, на которую стоит обратить внимание — это дополнительные отступы. Также, добавьте пустую строку сразу после break.
switch( variable ) {
case 0:
statements;
break;
case 1:
statements;
break;
default:
break;
}
Функции
Функции производят разные действия, и их наименование должно раскрывать эти действия. Поэтому, в наименование функции обязательно, включайте глагол действия этой функции. Без исключений! Используйте тот же метод написания, что и с переменными: маленький регистр, разделитель — подчёркивание. Такой метод позволит вам производить милые предложения в коде, которые будут понятны всем.
Также, удостоверьтесь, что функция делает именно то, что говорится в её имени — ни больше, ни меньше. Если у вас есть функция 'load_resources', убедитесь, что функция только ресурсы и загружает, ничего более, никаких других инициализаций. Зачастую существует соблазн, поместить по-быстрому в load_resources инициализацию разных переменных, потому что такая функция вызывается с большим приоритетом, но это принесёт больше проблем в будущем. Стиль deWiTTERS использует крайне мало комментариев, а функция должна производить только то, что написано в её имени. А когда функция возвращает что-то, убедитесь, что из имени функции будет понятно, что она возвращает.
Некоторые функции, как пара "инь и ян" — выполняют противоположные действия, и вы должны соответствовать этому в своих названиях для таких функций. Например: get/set, add/remove, insert/delete, create/destroy, start/stop, increment/decrement, new/old, begin/end, first/last, up/down, next/prev, open/close, load/save, show/hide, enable/disable, resume/suspend и т.д.
Вот, простой вызов функции. Используйте пробелы сразу после скобки и непосредственно перед закрывающей скобкой, как в случае с вызовом условия if. А также, оставьте по пробелу после запятых, как это делается в написании, в английском языке.
do_something( with, these, parameters );
Если вызов функции очень длинный, в силу большого количества параметров? Нужно разбить вызов на несколько отдельных строк. Выравнивайте следующие строки в соответствии с предыдущими, чтобы общая структура соответствовала сама себе, а разрывы делайте после запятых.
HWND hwnd = CreateWindow( "MyWin32App", "Cool application",
WS_OVERLAPPEDWINDOW,
my_x_pos, my_y_pos,
my_width, my_height,
NULL, NULL, hInstance, NULL );
Определение функции (definition)
Вот типичное описание функции:
bool do_something_today( with, these, parameters ) {
get_up();
go_to( work, car );
work();
go_to( home, car );
sleep();
return true;
}
Убедитесь, что ваша функция не слишком огромна. Или, цитируя Линуса:
Максимальная длина функции обратно пропорциональна сложности и уровню вложенности этой функции. Поэтому, если у вас есть концептуально простая функция, которая состоит из одного, длиннющего (но простого) case-вызова, где вы просто делаете кучу маленьких дел для огромного количества ситуаций — да, нормально, пусть будет длиннющая функция. Но если у вас есть сложная функция, и вы ожидаете, что более-менее-среднего-качества новичок-малоопытный студент-начинайка не сможет даже понять, о чём ваша функция, в принципе — тут вам стоило бы установить более строгие пределы. Используйте вспомогательные функции с хорошими, описательными названиями (вы даже можете сделать их in-line функциями, если считаете, что это повысит производительность и, возможно, это даже будет работать лучше, чем вы задумали ранее)
Классы
Для наименования классов я использую всё ту же ВерблюжьюРаскладку, как и для определения типов. И не стоит особо заморачиваться насчёт добавления префикса 'C' для каждого класса — это бессмысленная трата байт кода и времени на его набор.
Как и для всего остального: давайте классам обдуманные, чистые имена. Если класс является потомком класса "Window", назовите его "MainWindow".
Когда вы создаёте новый класс, запомните: всё начинается со структуры данных.
Данные доминируют. Если вы выбрали правильную структуру данных, всё правильно организовали, то алгоритмы будут почти всегда само-очевидными. Структура данных, не алгоритмы — главное в программировании.
Фред Брукс.
Наследование
Отношение “Is a” должно быть смоделировано как наследование (inheritance), а “has a” — как сдерживание (containment). Удостоверьтесь, что не переборщили с наследованием. Это отличная технология, но только при правильном применении.
Члены класса
Определённо, необходимо делать различие между членами класса и обычными переменными. Если вы не будете этого делать — в будущем вы об этом горько пожалеете. Возможными именами будут m_Member или fMember. Для динамических членов класса я бы использовал my_member, а для статических our_member. Такой метод позволяет получить неплохие предложения в теле ваших методов, например:
if( my_help_button.is_pressed() ) {
our_screen_manager.go_to( HELP_SCREEN );
}
Для всего остального, всё, касающееся наименований и применяемое к переменным, так же применимо и к членам класса. Единственная здесь проблема: я так и не смог для себя определить корректное наименование булевских членов класса. Вы помните, что логические значения должны иметь префикс "is" или "has". Но в комбинации с префиксом "my_" мы получаем безумие, типа "my_is_old" или "my_has_children". Я так и не смог найти хорошего решения для этой проблемы, если у вас есть предложения, пожалуйста, оставьте комментарий к этому посту.
Вы не должны объявлять члены класса как public. Иногда кажется, что такой метод реализации быстрее, и поэтому лучше, но, божежмой, как вы ошибаетесь (как и я много раз). Вы должны пройти через общедоступные (public) методы, чтобы добраться до членов класса.
Методы
Всё, что применимо к функциям, применимо и к методам, в полном объёме, вплоть до добавления глагола в имя метода. Так же, удостоверьтесь, что в имени метода нет наименования класса.
Структура кода
Выравнивайте похожие строки, чтобы дать вашему коду хороший внешний вид. Например:
int object_verts[6][3] = {
{-100, 0, 100}, {100, 0, 100}, { 100, 0, -100},
{-100, 11, 100}, (100, 0, -100}, {-100, 0, -100}
};
RECT rect;
rect.left = x;
rect.top = y;
rect.right = rect.left + width;
rect.bottom = rect.right + height;
Никогда не помещайте несколько операторов в одну линию, если для этого нет определённых оснований. Одним из таких оснований может быть однотипность строк, в случае объединения нескольких операторов на одной строке:
if( x & 0xff00 ) { exp -= 16; x >>= 16; }
if( x & 0x00f0 ) { exp -= 4; x >>= 4; }
if( x & 0x000c ) { exp -= 2; x >>= 2; }
Связанные по смыслу переменные одного типа можно объявлять в одном выражении, через запятую. Такой метод делает код более компактным и красивым для обзора одновременно. Но никогда не делайте этого с несвязанными по смыслу переменными!
int x, y;
int length;
Пространства имен и наборы библиотек
Пространства имен и названия пакетов должны быть написаны в нижнем регистре, без подчёркиваний. Используйте пространство имен для каждого модуля или слоя, и это принесёт больше понимания для вашего кода, для разных его слоёв.
Дизайн
Когда я начинаю проект, я не задумываюсь о дизайне. Я держу в голове глобальную структуру и просто начинаю писать код. Код сам по себе развивается, хотите вы этого, или нет. Поэтому, просто дайте ему шанс для развития.
Развивающийся код, со временем потребует переработки, и после некоторого времени программирования ваш текущий код становится плохим. Для сохранения хорошей структуры в коде я пользуюсь следующими правилами:
Когда функции становятся слишком большими, разбивай проблему на несколько вспомогательных функций.
Если класс содержит очень много членов и методов, разбей его на несколько вспомогательных классов и используй их в своём главном классе (но не используй для этого наследование!). Убедись, что вспомогательный класс не использует для работы основной, где бы то ни было.
Когда модуль начинает использовать слишком много классов, разбей его на большее количество модулей, где каждый модуль верхнего уровня использует модули более низких уровней.
Когда закончилось добавление нового функционала или завершилось исправление ошибки, перечитай все измененные файлы, чтобы убедиться, что всё находится в идеальном состоянии.
Некоторые проекты могут стать большими. Очень большими. Способом справиться с этим может быть разбиение вашего проекта на отдельные слои. На практике слои реализуются в виде пространств имён. Нижние слои используются верхними слоями. Каждый слой добавляет больше функциональности, доводя, в итоге эту функциональность до пользователя.
Файлы
Файлы нужно называть именем класса, который он содержит. Не держите в одном файле больше одного класса, и вы всегда будете знать где нужно искать тот или иной класс. Структура каталогов проекта представляет структуру пространств имён.
Структура файла .h
Заголовочные файлы языка C или C++ содержат интерфейс реализации. Очень важно знать это при создании .h файла. В классе, сначала, определяются public интерфейсы, которые можно будет использовать в других классах, затем определяются все protected методы и члены класса. Такой способ дизайна позволяет держать нужную для людей, пользующихся вашим классом, информацию в начале. Я не использую private методы или члены класса, поэтому все члены класса сгруппированы внизу объявления класса. Это позволяет быстрее осмотреть содержимое класса, снизу. Группируйте методы вместе, по их смыслу.
/*
* license header
*/
#ifndef NAMESPACE_FILENAME_H
#define NAMESPACE_FILENAME_H
#include <std>
#include "others.h"
namespace dewitters {
class SomeClass : public Parent {
public:
Constructor();
~Destructor();
void public_methods();
protected:
void protected_methods();
int my_fist_member;
double my_second_member;
const static int MAX_WIDTH;
};
extern SomeClass the_some_class;
}
#endif
Структура файлов .java и .cs
.java или .cs файлы содержат не интерфейсы класса, а просто их реализацию. А так как структура данных важнее алгоритма, определяйте члены класса перед методами. Такой подход даёт вам возможность быстрее осознать содержимое класса, через его структуру данных (члены класса). Схожие методы стоит сгруппировать вместе.
Схематичный обзор файлов .java или .cs:
/*
* license header
*/
package com.dewitters.example;
import standard.modules.*;
import custom.modules.*;
class SomeClass extends Parent {
public final int MAX_WIDTH = 100;
protected int my_first_member;
protected double my_second_member;
Constructor() {
}
Methods() {
}
}
Шутки
Программистам иногда хочется добавить шуток в их код, но есть те, кто такое не любит, такой способ развлечения. Как по мне: вы можете использовать шутки до тех пор, пока они не мешают чтению вашего кода и не мешают выполнению программы.
Стиль deWiTTERS vs. другие стили
Здесь я представлю вам живой код. Я украл некоторый код у других программистов и переписал его, используя свой стиль кодирования. Решите для себя, хорош мой стиль или не очень. Я считаю, что вы можете прочитать мой код быстрее, так как он короче, а все идентификаторы аккуратно переименованы.
Если вы думаете, что видели код, который может дать фору моему стилю кодирования, оставьте комментарий ниже. Я использую его в своём, улучшенном стиле 'deWiTTERS' и опубликую его.
Indian Hill C Style
/*
* skyblue()
*
* Determine if the sky is blue.
*/
int /* TRUE or FALSE */
skyblue()
{
extern int hour;
if (hour < MORNING || hour > EVENING)
return(FALSE); /* black */
else
return(TRUE); /* blue */
}
/*
* tail(nodep)
*
* Find the last element in the linked list
* pointed to by nodep and return a pointer to it.
*/
NODE * /* pointer to tail of list */
tail(nodep)
NODE *nodep; /* pointer to head of list */
{
register NODE *np; /* current pointer advances to NULL */
register NODE *lp; /* last pointer follows np */
np = lp = nodep;
while ((np = np->next) != NULL)
lp = np;
return(lp);
}
Rewritten to deWiTTERS Style:
bool sky_is_blue() {
return the_current_hour >= MORNING && the_current_hour <= EVENING;
}
Node* get_tail( Node* head ) {
Node* tail;
tail = NULL;
Node* it;
for( it = head; it != NULL; it = it->next ) {
tail = it;
}
return tail;
}
“Commenting Code” from Ryan Campbell
/*
* Summary: Determine order of attacks, and process each battle
* Parameters: Creature object representing attacker
* | Creature object representing defender
* Return: Boolean indicating successful fight
* Author: Ryan Campbell
*/
function beginBattle(attacker, defender) {
var isAlive; // Boolean inidicating life or death after attack
var teamCount; // Loop counter
// Check for pre-emptive strike
if(defender.agility > attacker.agility) {
isAlive = defender.attack(attacker);
}
// Continue original attack if still alive
if(isAlive) {
isAlive = attacker.attack(defender);
}
// See if any of the defenders teammates wish to counter attack
for(teamCount = 0; teamCount < defender.team.length; i++) {
var teammate = defender.team[teamCount];
if(teammate.counterAttack = 1) {
isAlive = teammate.attack(attacker);
}
}
// TODO: Process the logic that handles attacker or defender deaths
return true;
} // End beginBattle
Rewritten to deWiTTERS Style:
function handle_battle( attacker, defender ) {
if( defender.agility > attacker.agility ) {
defender.attack( attacker );
}
if( attacker.is_alive() ) {
attacker.attack( defender );
}
var i;
for( i = 0; i < defender.get_team().length; i++ ) {
var teammate = defender.get_team()[ i ];
if( teammate.has_counterattack() ) {
teammate.attack( attacker );
}
}
// TODO: Process the logic that handles attacker or defender deaths
}
Здесь статья Коэна заканчивается. От себя добавлю, что после её прочтения я перешёл в своих работах на js и abl на стиль с подчёркиванием и не жалею. Надеюсь, данная работа была для вас полезной.
Комментарии (30)
dyadyaSerezha
00.00.0000 00:00+9if, while, for и т.д. - не операторы, а ключевые слова. И выражение if( a > 1 ) выглядит больше как вызов функции. Короче, не согласен. Тем более, что он ссылается в начале к естественному языку, так вот в естественных языках слова в скобках никогда не отделяются пробелами от скобок.
И вообще, какая разница, насколько хорош или плох данный стиль, если в большинстве организаций принят свой.
Далее, в примерах по рестилизации он грубо меняет сам код, а это уже вообще не про стиль.
alexvgrey Автор
00.00.0000 00:00Про операторы - это ко мне больше. Текст и так был большой, где-то его можно еще сократить, но не хотел отходить от оригинала. Я думаю, если поменять в этом тексте слово "оператор" на "ключевое слово", смысл не особо изменится.
В угоду лучшей видимости кода автор, всё же пренебрёг правилом "должно быть как естественный язык", тем более, что он поясняет это целостностью оператора (функции), в случае, если "прилепить" скобку к ключевому слову (имени функции).
Ну вот, например, из последнего:
Про организации - сто процентов, Ваша правда, но подкорректировать личный стиль кода никто не мешает. На скриншоте тоже видно, что у меня нет возможности быть "адептом стиля deWiTTERS", но что-то можно использовать. Вы же не используете стиль кода, которым писали в своей первой организации, во всех последующих?
А про изменение кода - это его профдеформация, как программиста. Я, например, часто не могу пройти мимо кода в продуктах своей организации, если там откровенный колхоз. Ну, правда, не всегда получается прямо хорошо сделать - тронешь где-то в одном месте, посыпется в другом. Надеюсь понятна моя мысль.
sourcerer
00.00.0000 00:00Если речь о C++, то “statement” лучше переводить как «инструкция», а “operator” как «оператор». И тогда не будет никакой путаницы.
18741878
00.00.0000 00:00+11Лишнее подтверждение тому, что весна - время обострения некоторых симптомов. Вечный и неизлечимый холивар: как расставлять скобки, нужны ли пробелы между скобками и переменными и т.п. Какое уже десятилетие это длится и сколько еще будет продолжаться...
alexvgrey Автор
00.00.0000 00:00Я думал, что первые комментарии будут как раз про ВерблюжьюТему и тему_с_подчёркиваниями :)
18741878
00.00.0000 00:00+4В каждом языке программирования принят свой стиль именования, которого придерживаются подавляющее большинство разработчиков. В Rust и Python - подчеркивания, в Java и Go - верблюжий регистр. Что тут обсуждать - это стандарт кодирования. Конечно, его можно нарушать (что некоторые и делают), но это mauvais ton. Ничего оригинального эти "реформаторы" не привносят - только вызывают раздражение, когда приходится разбираться с их бескультурными поделками :)
alexvgrey Автор
00.00.0000 00:00По поводу стилистики наименования элементов в разных языках — немного отдаёт самозатворничеством. Не считаю моветоном использование в своей программе стилистики, которая устраивает меня. Оговорюсь, что это не касается продуктов, которые разрабатываются командой, особенно там, где есть соглашение о коде. В своих работах пользуюсь подчёркиваниями в abl, в том числе (в Java пробовал - нормально выглядит). Хотя в abl чаще пользуются вообще, венгерской нотацией.
Как и большинство изучающих языки программирования, стараюсь читать документацию. Если в документации, создатели языка говорят о регистронезависимости операторов или ключевых слов - я пользуюсь этой информацией. Ну, скажем так, я не адепт больших букв в запросах к БД. Когда погружен в язык, нет необходимости выделять ключевые слова прописью, особенно с текущим уровнем различных редакторов и IDE. Да, есть огромное количество мест, где: не то, что цвета, вообще вёрстки толком нет — но и там, я знаю, большие буквы в select'е не становятся панацеей для удобства. Всё равно придётся прочитать всё, чтобы понять, что происходит, если код не твой. Если твой, то точно: большие буквы в тексте не ускорят процесс понимания и фиксации. Надеюсь, понят правильно.
Насчёт реформаторов - полностью с Вами согласен. Оригинального мало, но есть полезное. Я не защищаю, в данном случае Коэна Уиттерса, ну просто для себя нашёл некоторые полезные моменты, которые применил на практике.
VYudachev
00.00.0000 00:00Ну к слову, как-то привык, что верблюжьяТема и PascalCase это немного разные вещи.
gmtd
00.00.0000 00:00+5В статье описывается просто code style. От названия статьи ожидания чего-то большего, про идеологию и методологию кодинга. А тут даже мантр design patterns нет...
alexvgrey Автор
00.00.0000 00:00Согласен с Вами. Но я ни добавил, ни убавил. Ровно так, как написал автор статьи. Первое его предложение разрушает Ваши ожидания.
mitasov-ra
00.00.0000 00:00Всё же лучше добавить. Статья прикольная, холивары про стиль разводить это всегда весело, но название всё портит. Получается дешёвый кликбейт, на который и я попался.
alexvgrey Автор
00.00.0000 00:00Соглашусь. Добавил. Хотя, когда писал этот пост, даже не думал о кликбейте.
Но, всё равно, спасибо за живую критику и обратную связь.
YuryZakharov
00.00.0000 00:00+1Ну, а что ожидать от человека, который
Когда я начинаю проект, я не задумываюсь о дизайне.
smart_alex
00.00.0000 00:00+3В статье много полезных советов, но в целом — это субъективный подход одного автора к программированию и можно оспорить как минимум 50% его рекомендаций.
Также немного смущает его стиль подачи: вместо «я предпочитаю делать так» он директивно и безальтернативно утверждает «должно быть так».
Также не встретил в статье упоминания о моём любимом и крайне полезном стиле «табличной» записи повторяющихся однотипных фрагментов кода — этот метод экономит кучу времени и позволяет легко выявлять трудноуловимые ошибки.
Zifix
00.00.0000 00:00Где про него можно почитать?
smart_alex
00.00.0000 00:00+1Про него можно почитать в моём комментарии :)
В коде используется табуляция в 2 пробела. Если в коде встречаются однотипные фрагменты, то они «форматируются» в виде таблицы (однотипные элементы один под другим), несмотря на тип кода — это могут быть массивы, функции, просто фрагменты кода или любые другие структуры.
Это:
Позволяет экономить место на экране и видеть больше кода
Сразу выявляется «паттерн» однотипных участков и самого алгоритма
Становится видно как уменьшить и оптимизировать код
При табличной записи становятся видны трудноуловимые ошибки в названиях переменных и их значениях
Единственное ограничение — ширина экрана — не стоит делать километровые листинги в ширину. Также этот метод нужно применять без фанатизма и только там, где это уместно.
Пример:
void sendHtmlAnswer(EthernetClient cl) {cl.println(makeAnswer(F("text/html")));} void sendCssAnswer (EthernetClient cl) {cl.println(makeAnswer(F("text/css")));} void sendJsAnswer (EthernetClient cl) {cl.println(makeAnswer(F("application/javascript")));} void sendPngAnswer (EthernetClient cl) {cl.println(makeAnswer(F("image/png")));} void sendJpgAnswer (EthernetClient cl) {cl.println(makeAnswer(F("image/jpeg")));} void sendGifAnswer (EthernetClient cl) {cl.println(makeAnswer(F("image/gif")));} void sendXmlAnswer (EthernetClient cl) {cl.println(makeAnswer(F("text/xml")));} void sendIcoAnswer (EthernetClient cl) {cl.println(makeAnswer(F("image/x-icon")));}
При обычном подходе этот код растянулся бы на несколько экранов вниз и слился бы в кашу без размера и структуры. И в этом коде нереально было бы заметить, например, ошибку в типах файлов.
alexvgrey Автор
00.00.0000 00:00За что я люблю Хабр и рад стать частью этого комьюнити. В комментариях, зачастую, можно найти огромное количество полезной информации и именно из-за Хабра я стал больше читать комментариев, под разными постами, на разных ресурсах.
Вам огромное спасибо за способ записи. С разбега сразу не гуглится. На Вашем примере отодвинул бы правые скобки к третьей строке, чтобы в глаза сразу бросился параметр функции. Простите за душность))
DenisPantushev
00.00.0000 00:00+1Почему автор пишет "Определение функции (definition)"
Но предлагает писать "if( x != y )"?
vfreelancer
00.00.0000 00:00Написанное должно быть абсолютно понятным настолько, насколько это вообще возможно. - какой смысл в этом правиле? это как в тз требование "дизайн должен быть приятен и удобен пользователю" - признак дилетанта, неумеющего писать тз
123Zero
00.00.0000 00:00Но в комбинации с префиксом "my_" мы получаем безумие, типа "my_is_old" или "my_has_children". Я так и не смог найти хорошего решения для этой проблемы, если у вас есть предложения, пожалуйста, оставьте комментарий к этому посту.
i_am_old и i_have_children. Все просто.
alexvgrey Автор
00.00.0000 00:00Я подозреваю, что автор имел ввиду, что если мы члены класса называем с префиксом my_, но при этом член класса - поле булевского типа (которые, по задумке автора стоит именовать с префиксами is_ или has_), то получается каша. Если принять во внимание Ваше предложение, получается, что для натуральности кода как языка - отлично, для понимания: что перед нами, переменная, поле класса, какого типа - неоднозначно.
Да, есть еще контекст, но тогда система его вроде не работает, получается))
firehacker
00.00.0000 00:00Когда-нибудь автор переболеет своей категоричности и эволюционирует до m_bHasChildren или m_fInitialized.
TiGR
00.00.0000 00:00+1Code style, среди прочего создаётся и для упрощения коллективной работы, в том числе, вводятся правила, которые уменьшают или полностью исключают изменения соседних строк. Отсюда всевозможные правила про висячие запятые, и запрет колоночного выравнивания.
А тут оно цветет пышным цветом. Но стоит вам добавить ещё одно свойство в класс, чуть более длинное, чем имеющиеся и вот, для поддержания красоты нужно менять несколько соседних строк.
В итоге ваш blame становится бессмысленным, а поиск через него первоначального коммита превращается в занимательный квест, а мерджи и число строк требующих ревью растёт непомерно.
alexvgrey Автор
00.00.0000 00:00Согласен, в коллективной работе code style должен учитывать особенности кода продукта, разрабатываемого командой.
Но для личного code style оно вполне себе может работать.
firehacker
00.00.0000 00:00По идее, blame (должно быть) можно настроить так, чтобы он не считал чисто-пробельные внутристрочные модификации за полноценные и при обнаружении таких продвигался глубже по графу коммитов.
Я пишу «должно быть», потому что на вкус и цвет все
фломастерыVCS разные, но вgit blame
это ключик-w
, например.TiGR
00.00.0000 00:00Вопрос лишь в том, поддерживают ли это всевозможные GUI, которые используются при анализе/ревью кода, типа всяких IDE или гитхабов с гитлабами
AlchemistDark
00.00.0000 00:00Буду знать, что если скобки от содержимого этих скобок отделяли пробелами, то это не что-то странное, а deWiTTERS
vilgeforce
"стиль мой настолько неизвестен" - то есть автор хочет сказать, что pylint на его коде кучу предупреждений выдаст?
alexvgrey Автор
Было бы интересно посмотреть, кстати. pylint с 2004-го существует, статья 2009 года. Возможно тогда у них была какая-то синхронизация. Но, вопрос интересный.
AlchemistDark
Думаю, линтер для Dart/Flutter тоже.