3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909

Coding Conventions Rationale

25.09.2014, 14:36. Показов 2772. Ответов 32
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
В повседневной практике мы работаем над разного рода проектами. Будь то суровые enterprise решения, высоконагруженные сервисы или же интерфейсы пользователей, небольшие функциональные прототипы. Мы работаем над коммерческими продуктами или хобби проектами, а может быть и над чисто академическими программами. В любом случае, всегда хочется верить, что труды будут кому-нибудь полезны, а если и пойдут под нож, то станут бесценным опытом.

Но стоит только дать повод - всегда найдутся люди, которые побросают работу и будут поддерживать холивары о расстановке фигурных скобок, пробелов и стиле именования переменных. Тем не менее, я считаю, что есть некоторые соглашения, для соблюдения которых имеются вполне объективные причины. Ниже хочется описать их, немного разбавив вкусовщиной. Быть может, в ответ форумчане вспомнят что-нибудь интересное.

0. Ограничение максимальной длины строки
Какое значение выбрать - дело вкуса, но ограничение должно быть. Указываю это правило под нулевым номером, поскольку несоблюдение нижеизложенных автоматически ведет к невозможности придерживаться этого соглашения.

1. Вертикальное выравнивание
Правило простое - вертикальное выравнивание в коде должно отсутствовать. Если легкость чтения такого кода еще можно назвать субъективной, то поспорить с трудностью поддержки уже сложнее.
Пример.
Пусть имеется вот такой код (взят в одной из тем форума):
C++
1
2
3
4
5
6
int     func
            (
                std::string     const   &   s,
                int                     &   a,
                int                     *   b
            );
Это объявление функции, принимающей три аргумента. Взгляд цепляется за множество непривычных элементов оформления, но я остановлюсь только на выравнивании аргументов. Код пишется не единожды. Вполне реальна ситуация, когда в функцию придется добавить еще аргументы. Предположим, необходимо добавить один аргумент:
C++
1
2
3
4
5
6
7
int     func
            (
                std::string     const   &   s,
                int                     &   a,
                int                     *   b,
                std::vector<Instrumental> const & data
            );
Очевидно, что форматирование нарушено. Теперь необходимо выровнять все прочие аргументы для поддержания стиля.
C++
1
2
3
4
5
6
7
int     func
            (
                std::string               const &   s,
                int                             &   a,
                int                             *   b,
                std::vector<Instrumental> const &   data
            );
Т.е. ради добавления одной строчки программисту пришлось переключать внимание на чисто механическую правку других строк кода, с точки зрения функционала не требующих изменений. Фактически необходимых правок всего две:
1. Добавление строки с аргументом.
2. Добавление запятой у предыдущего аргумента.

Последствия.
1. Код сложно поддерживать.
2. Стиль не является diff-friendly.
Мы постоянно смотрим диффы. В истории коммитов, в код ревью. Что будет показано людям в случае подобных изменений?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ diff -ru first.cpp second.cpp
--- first.cpp   2014-09-25 12:39:17.444961057 +0700
+++ second.cpp  2014-09-25 16:52:10.352839450 +0700
@@ -1,7 +1,8 @@
 int     func
             (
-                std::string     const   &   s,
-                int                     &   a,
-                int                     *   b
+                std::string               const &   s,
+                int                             &   a,
+                int                             *   b,
+                std::vector<Instrumental> const &   data
             );
Функциональное изменение в одной строке и синтаксическое в другой смешиваются с необходимыми для поддержания стиля изменениями форматирования. Читающий патч вынужден посимвольно сравнивать строки без функциональных изменений.

Альтернативный вариант.
C++
1
2
3
4
int func(
    const std::string& s,
    int& a,
    int* b);
C++
1
2
3
4
5
int func(
    const std::string& s,
    int& a,
    int* b,
    const std::vector<Instrumental>& data);
C++
1
2
3
4
5
6
7
8
9
10
$ diff -ru first.cpp second.cpp
--- first.cpp   2014-09-25 16:59:46.396835795 +0700
+++ second.cpp  2014-09-25 17:00:10.996835598 +0700
@@ -1,5 +1,6 @@
 int func(
     const std::string& s,
     int& a,
-    int* b);
+    int* b,
+    const std::vector<Instrumental>& data);
2. Стиль форматирования не должен противоречить правилам типографии
Вкусовщина. Добавлена лишь потому, что предыдущий пример некоторые предлагают оформить следующим образом:
C++
1
2
3
4
int func(const std::string& s
    , int& a
    , int* b
);
C++
1
2
3
4
5
int func(const std::string& s
    , int& a
    , int* b
    , const std::vector<Instrumental>& data
);
C++
1
2
3
4
5
6
7
8
9
$ diff -ru first.cpp second.cpp
--- first.cpp   2014-09-25 17:04:39.856833443 +0700
+++ second.cpp  2014-09-25 17:05:00.260833280 +0700
@@ -1,5 +1,6 @@
 int func(const std::string& s
     , int& a
     , int* b
+    , const std::vector<Instrumental>& data
 );
Да, удалось еще сократить дифф на одну функционально незначимое изменение. Цена - повсеместное неестественное форматирование кода. Лично мое мнение: одна "лишняя" строчка в диффе - меньшее зло, чем нарушение общепринятых правил типографии. Читая код, я ожидаю, что как и в текстах книг/статей:
1. Перед запятой отсутствует пробельный символ. После запятой ставится пробел.
2. Знаки арифметических операций отделены одним пробелом с каждой стороны, за исключением унарных операций.
3. Перед открывающей круглой скобкой ставится пробел. После скобки пробел отсутствует. А вот вызов функции уже тяготеет к математической нотации, поэтому в этом случае пробел перед скобкой опускается.

3. Код внутри пространств имен пишется без дополнительного отступа
В пользу этого правила можно приводить различные аргументы. Можно говорить,что нам не нужны дополнительные уровни вложенности. Особенно если в проекте присутствует множество вложенных пространств имен (см ограничение на длину строки). Можно рассуждать о блоках кода и отмечать семантическую разницу между телом функции и телом пространства имен. Но лично мне привычнее опираться на повседневные практики, а как я уже отмечал выше, одна из таких - это использование diff.
Для примера я взял псевдокод алгоритма Дейкстры. Сейчас не важна его компилируемость и прочие элементы стиля, за исключением отступа внутри пространства имен.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
namespace graph {
 
const int INF = 1000000000;
 
void dijkstra()
{
    int n;
    // ... чтение n ...
    vector<vector<pair<int, int>>> g(n);
    // ... чтение графа ...
    int s = ...; // стартовая вершина
 
    vector<int> d (n, INF),  p (n);
    d[s] = 0;
    set<pair<int, int>> q;
    q.insert(make_pair(d[s], s));
 
    while (!q.empty())
    {
        int v = q.begin()->second;
        q.erase(q.begin());
 
        for (size_t j = 0; j < g[v].size(); ++j)
        {
            int to = g[v][j].first;
            int len = g[v][j].second;
 
            if (d[v] < d[to])
            {
                q.erase(make_pair(d[to], to));
                d[to] = d[v] + len;
                p[to] = v;
                q.insert(make_pair(d[to], to));
            }
        }
    }
}
 
}
В коде есть принципиальный баг. После его исправления дифф будет выглядеть следующим образом:
C++
1
2
3
4
5
6
7
8
9
10
11
12
$ diff -rup first.cpp second.cpp
--- first.cpp   2014-09-25 17:26:57.060822726 +0700
+++ second.cpp  2014-09-25 17:26:51.700822769 +0700
@@ -25,7 +25,7 @@ void dijkstra()
             int to = g[v][j].first;
             int len = g[v][j].second;
 
-            if (d[v] < d[to])
+            if (d[v] + len < d[to])
             {
                 q.erase(make_pair(d[to], to));
                 d[to] = d[v] + len;
Здесь важна четвертая строка:
C++
1
@@ -25,7 +25,7 @@ void dijkstra()
Утилита diff способна показать контекст, в котором были сделаны изменения - имя функции. Понятно, что поиск строки реализован не честным парсингом кода, а поиском ближайшей строки без отступа. Следовательно, если внутри пространства имен код будет с отступом, то максимум, что мы увидим в контексте - это имя неймспейса:
C++
1
2
3
4
5
6
7
8
9
10
11
12
$ diff -rup first.cpp second.cpp
--- first.cpp   2014-09-25 17:31:16.884820644 +0700
+++ second.cpp  2014-09-25 17:31:25.108820578 +0700
@@ -25,7 +25,7 @@ namespace graph {
                 int to = g[v][j].first;
                 int len = g[v][j].second;
 
-                if (d[v] < d[to])
+                if (d[v] + len < d[to])
                 {
                     q.erase(make_pair(d[to], to));
                     d[to] = d[v] + len;
Учитывая, что функций в пространстве имен может быть N, этой информации недостаточно для быстрого определения контекста.

Справедливости ради стоит отметить, что для поиска функции diff может использовать регулярное выражение, но в этот момент у меня включается лень: ни писать, ни гуглить регулярку для этого случая не хочется.

Других правил оформления кода, обусловленных практическими потребностями, мне пока не вспоминается. Если есть идеи - welcome.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
25.09.2014, 14:36
Ответы с готовыми решениями:

Куда делись Code Conventions for the Java Programming Language?
Как бы за ссылкой ничего нет - посмотреть, файлы скачать нельзя: http://www.oracle.com/technetwork/java/codeconv-138413.html Где...

Good Coding Practices
123 Добавлено через 1 час 1 минуту Всем привет. Примитивнейшая задача: два класса обмениваются значениями переменных. Два объекта,...

SOS Coding Input
Добрый день. Ребята очень нужна помощь на вас надежда. Смотрите суть такова: Если таблица в базе MYSQL на сервере. Я...

32
Модератор
Эксперт CЭксперт С++
 Аватар для sourcerer
5288 / 2376 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
06.10.2016, 20:30
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Mr.X Посмотреть сообщение
Неужели это можно прочитать?!
Можно.

Цитата Сообщение от Mr.X Посмотреть сообщение
А в обратную сторону он умеет?
Не знаю. Вроде бы, нет.

Добавлено через 12 минут
Цитата Сообщение от Mr.X Посмотреть сообщение
Да, непарные скобочки особенно впечатляют!
Я лично отформатировал бы так

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// 1.
 
//У вас имеются два билета. Номер первого билета равен M, второго – N.
//Лимиты M и N: 10000000 ? M < N ? 99999999.
//Ваша задача определить количество "счастливых билетов" в данном диапазоне.
//Билет "счастливый", если сумма первых 4 цифр равна сумме последних 4 цифр.
//Ввод:
//Вводятся номера двух билетов.
 
//Вывод
//Количество "счастливых билетов" в данном диапазоне.
 
//Пример:
// a: 11111110
// b: 11111112
// ans: 1
 
// a: 10000000
// b: 99999999
// ans: 4379055
 
#include <algorithm>
#include <cmath>
#include <iostream>
#include <map>
 
typedef long long T_int;
typedef std::map <T_int, T_int> T_count_of_sum;
 
T_int sum_digits( T_int n )
{
    T_int res{};
    
    do
    {
        res += n % 10;
        n /= 10;
    }
    while ( n );
    
    return res;
}
 
void fill_count_of_tail_dig_sum
    (
        T_int min,
        T_int max,
        T_int mod,
        T_count_of_sum &count_of_sum
    )
{
    for ( T_int n{ min }; n <= max; ++n )
    {
        ++count_of_sum[ sum_digits( n % mod ) ];
    }
}
 
T_int winning_tickets_count_in_segment
    (
        T_int min,
        T_int max
    )
{
    T_count_of_sum count_of_sum_L;
    T_count_of_sum count_of_sum_R;
    T_int num_len = std::to_string( max ).size();
    T_int mod = std::pow( 10, num_len / 2 );
    
    fill_count_of_tail_dig_sum
        (
            min / mod,
            max / mod,
            mod,
            count_of_sum_L
        );
    
    fill_count_of_tail_dig_sum
        (
            min,
            std::min( min + mod - 1, max ),
            mod,
            count_of_sum_R
        );
    
    T_int res{};
    
    for ( T_int sum{}; sum <= 9 * num_len / 2; ++sum )
    {
        res += count_of_sum_L[ sum ] * count_of_sum_R[ sum ];
    } // for
    
    return res;
}
 
int main()
{
    T_int a{};
    T_int b{};
    
    std::cin >> a >> b;
    
    std::cout << winning_tickets_count_in_segment( a, b ) << std::endl;
}
0
Эксперт С++
 Аватар для Mr.X
3225 / 1752 / 436
Регистрация: 03.05.2010
Сообщений: 3,867
06.10.2016, 20:39
Цитата Сообщение от gru74ik Посмотреть сообщение
Можно.
Не верю! Вот, по сравнению с этим извращением, мой стиль - просто верх невинности!
Цитата Сообщение от gru74ik Посмотреть сообщение
Вроде бы, нет.
Ну вот, ни на что толковое он таки не годен!

Добавлено через 8 минут
Цитата Сообщение от gru74ik Посмотреть сообщение
Я лично отформатировал бы так
Цитата Сообщение от gru74ik Посмотреть сообщение
C++
1
res += count_of_sum_L[ sum ] * count_of_sum_R[ sum ];
Т.е., по-вашему, это более читаемо? Чем мотивируете?
0
Модератор
Эксперт CЭксперт С++
 Аватар для sourcerer
5288 / 2376 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
06.10.2016, 21:06
Цитата Сообщение от Mr.X Посмотреть сообщение
Т.е., по-вашему, это более читаемо? Чем мотивируете?
Ничем. Я художник, я так вижу. Макконнелл, правда, видит так же, но это так, к слову. Вы делайте как хотите. Свой код форматирую так, как хочу. В IT-корпорации всё равно все поголовно будем соблюдать корпоративный кодстайл.
1
Диссидент
Эксперт C
 Аватар для Байт
27714 / 17332 / 3810
Регистрация: 24.12.2010
Сообщений: 38,978
06.10.2016, 21:32
Цитата Сообщение от gru74ik Посмотреть сообщение
Я художник, я так вижу.
Золотые слова!
0
 Аватар для Ghost Writter
53 / 53 / 19
Регистрация: 09.12.2015
Сообщений: 215
07.10.2016, 01:33
Цитата Сообщение от gru74ik Посмотреть сообщение
Ничем. Я художник, я так вижу. Макконнелл, правда, видит так же, но это так, к слову. Вы делайте как хотите. Свой код форматирую так, как хочу. В IT-корпорации всё равно все поголовно будем соблюдать корпоративный кодстайл.
gru74ik, "Макконнелл, правда, видит так же, но это так, к слову."

Чой-то?) Вот дочитываю его книгу. Там везде верблюжийСтиль. И вообще там не одна глава на эту тему.
0
Модератор
Эксперт CЭксперт С++
 Аватар для sourcerer
5288 / 2376 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
07.10.2016, 06:49
Цитата Сообщение от Ghost Writter Посмотреть сообщение
Чой-то?)
Той-то. Я про отступы внутри квадратных и круглых скобок говорил. Нижние_подчёркивания или верблюжийСтиль - про это вообще речи не шло.
0
Неэпический
 Аватар для Croessmah
18150 / 10732 / 2067
Регистрация: 27.09.2012
Сообщений: 27,047
Записей в блоге: 1
07.10.2016, 07:54
Цитата Сообщение от Mr.X Посмотреть сообщение
Неужели это можно прочитать?!
Большей частью пользуюсь именно
C++
1
2
some {
}
а не
C++
1
2
3
some
{
}
меня второе вообще бесит.
0
 Аватар для Martein
704 / 109 / 21
Регистрация: 22.06.2014
Сообщений: 241
07.10.2016, 08:17
Mr.X,, Я долго ждал, когда его стайл коллективно забросают какашками. Да, и в обратную сторону он умеет. Просто берёте сайт https://clangformat.com/ и создаёте свои правила, а потом генерируете файл конфигурации для этого своего стайла и прикручиваете к clang-format, но я очень надеюсь, что у вас не получится. =)
2
Модератор
Эксперт CЭксперт С++
 Аватар для sourcerer
5288 / 2376 / 342
Регистрация: 20.02.2013
Сообщений: 5,773
Записей в блоге: 20
07.10.2016, 09:22
Цитата Сообщение от Mr.X Посмотреть сообщение
А в обратную сторону он умеет?
Тут мне Martein подсказал - он по всякому умеет. Как настроите, так и будет.

Добавлено через 55 секунд
Martein, опередил меня
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
08.10.2016, 23:34
Цитата Сообщение от Ghost Writter Посмотреть сообщение
Чой-то?) Вот дочитываю его книгу. Там везде верблюжийСтиль. И вообще там не одна глава на эту тему.
такое впечатление, что вы не въехали ни в то,
о чем вам писал господин gru74ik

ни в то, о чем пишет господин Макконелл.

Цитата Сообщение от Croessmah Посмотреть сообщение
меня второе вообще бесит.
а мне уже пофигу, что так, что этак.
главное что бы не такое уг, как у господина Mr.X
0
 Аватар для Ghost Writter
53 / 53 / 19
Регистрация: 09.12.2015
Сообщений: 215
09.10.2016, 09:00
hoggy, скорее пример некорректен. Я и не понял, что дело в скобках, ведь чтобы узнать для чего они нужны надо и другие элементы прочитать и понять.

В книге то Макконелл использует

C++
1
2
3
SomeName(){
     //....
}
Хотя это больше напоминает, если бы писал на Java (ток имя метода с нижнего регистра начинается). Там видимо, из-за специфичных языку элементов удобно так писать.

В большинстве примеров из книг и статей на C++ я видел такое форматирование:

C++
1
2
3
4
someName()
{
     //....
}
И оно мне поудобнее будет. Хотя Макконелл приводит рассуждения, что так нельзя выделить управляющую структуру.

Но недавно встретил упоминание, уже не помню где, что имя метода лучше начинать с большой буквы, дабы выделить, что это метод класса.

Такой код можно встретить в студии используя проекты C#

C#
1
2
3
4
SomeName()
{
     //....
}
Я был бы рад, если кто-т просветит в этом деле, потому что опыта написания больших проектов у меня нет. Если подскажите - буду рад.
0
Неэпический
 Аватар для Croessmah
18150 / 10732 / 2067
Регистрация: 27.09.2012
Сообщений: 27,047
Записей в блоге: 1
09.10.2016, 10:05
Цитата Сообщение от hoggy Посмотреть сообщение
а мне уже пофигу, что так, что этак.
Мне тоже, код Mr.X тоже нормально читаю,
но всё же хочется хорошего для себя.
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
09.10.2016, 11:44
Цитата Сообщение от Croessmah Посмотреть сообщение
код Mr.X тоже нормально читаю
я его код вообще не читал)))
даже не пытался.
как глянул на "это", сразу подумал: "а оно мне вообще надо?"
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
09.10.2016, 11:44

Где почитать о Coding convention for C#?
Товарищи дайте п-та сылку, где можно это прочитать! Заранее благодарю!!!

Coding style или нет
Услышал сегодня от коллеги такую интересную вещь: есть блоки кода ограниченные командными скобками {}. Так вот, рекомендуется переменные,...

e-mail html format and coding problem
Значится генерю я письмо: Set mail = Server.CreateObject('CDONTS.NewMail') mail.BodyFormat = 0 ' письмо в HTML виде ...

Как разбить код на 2 функции: Coding и Decoding?
#include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;map&gt; #include &lt;list&gt; #include &lt;fstream&gt; using namespace std; ...

CMA Gorenje W72Y2 sensocare, coding and test
Gorenje W72Y2 TYP PS10/13080 Art: 392721/03 SensoCare 7Kg 800 RPM Proc: R5F100 Pcb:353288 colleague please explain with...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
33
Ответ Создать тему
Опции темы

Новые блоги и статьи
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru