Форум программистов, компьютерный форум, киберфорум
Священные войны
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
3258 / 2060 / 351
Регистрация: 24.11.2012
Сообщений: 4,909

Coding Conventions Rationale

25.09.2014, 14:36. Показов 2717. Ответов 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
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,038
Записей в блоге: 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
18149 / 10731 / 2067
Регистрация: 27.09.2012
Сообщений: 27,038
Записей в блоге: 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
Ответ Создать тему
Новые блоги и статьи
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru