Правила и стандарты оформления кода программ

В этой статье хочу немного рассказать об основных правилах оформления кода программ, а именно о том, как сделать его хорошо читаемым и понятным. Как ни странно, но об этом очень мало написано в книгах по программированию и, по-моему, зря. Тем не менее, практически все опытные программисты пишут красивый, умный и понятный код, а следовательно, это действительно важный момент в обучении программированию. И очень желательно к хорошему тону написания кода программ привыкать сразу. Как сейчас, вспоминаю, еще в школе на уроке русского языка, учитель часто мне говорила, что строки писать, нужно начиная от края, за это она даже снижала мне оценку. Я же привык писать не от самого края, а делать отступы. Сейчас думаю, что она была абсолютно права, т.к. есть определенные правила хорошего тона и стандарты, которые нужно выполнять. Также она часто ругала тех, кто делал маленькие отступы между слов, что они сливались воедино, и не было понятно слитно они написаны или нет. Хочу сказать, что в языках программирования несколько подобная ситуация, но обо всем по порядку.

1. Первое и, пожалуй, самое важное правило - это отступы, а точнее горизонтальные отступы. У нас в университете даже отказывались принимать листинги программ, в которых нет отступов, либо они сделаны не правильно. Зачем нужны отступы мы рассмотрим на следующем примере

Первым привожу код программы без отступов, оцените его удобство. Программа сортирует строки двумерного массива по возрастанию (каждую строку в отдельности). Если вам нужна полная сортировка массива, то найти вы ее сможете в разделе Алгоритмы.

//Сортируем пузырьком строки двумерного массива
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <time.h>
void printMatrix(int[][10], const int);
using namespace std;
int main()
{
const int SIZE = 10;
int matrix[SIZE][SIZE];
int temp;
srand(time(NULL));
//заполняем массив случайным образом
for(int i = 0; i < SIZE; i++)
for(int j = 0; j < SIZE; j++)
matrix[i][j] = 1 + rand() % 100;
//сортируем пузырьком
for(int N = 1; N < SIZE * SIZE; N++)
{
for(int i = 0; i < SIZE; i++)
{
for(int j = 0; j < SIZE - 1; j++)
{
if(matrix[i][j + 1] < matrix[i][j])
{
temp = matrix[i][j + 1];
matrix[i][j + 1] = matrix[i][j];
matrix[i][j] = temp;
}
}
}
}
printMatrix(matrix, SIZE);
return 0;
}
//печать массива
void printMatrix(int mx[][12], const int SIZE)
{
for(int i = 0; i < SIZE; i++)
{
cout << endl;
for(int j = 0; j < SIZE; j++)
cout << setw(4) << mx[i][j];
cout << endl;
}
}

Ну как вам такой листинг программы? По-моему его читать просто невозможно, либо очень и очень тяжело. А все потому, что программист не использует отступы. Как говориться: истина познается в сравнении. Смотрим этот же код, но написанный по всем правилам отступов.

//Сортируем пузырьком строки двумерного массива

#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <time.h>

void printMatrix(int[][10], const int);

using namespace std;

int main()
{
    const int SIZE = 10;
    int matrix[SIZE][SIZE];
    int temp;
    srand(time(NULL));

    //заполняем массив случайным образом
    for(int i = 0; i < SIZE; i++)
        for(int j = 0; j < SIZE; j++)
            matrix[i][j] = 1 + rand() % 100;

    //сортируем пузырьком
    for(int N = 1; N < SIZE * SIZE; N++)
    {
        for(int i = 0; i < SIZE; i++)
        {
            for(int j = 0; j < SIZE - 1; j++)
            {
                if(matrix[i][j + 1] < matrix[i][j])
                {
                   temp = matrix[i][j + 1];
                   matrix[i][j + 1] = matrix[i][j];
                   matrix[i][j] = temp;
                }
            }
        }
    }

    printMatrix(matrix, SIZE);

    return 0;
}

//печать массива
void printMatrix(int mx[][12], const int SIZE)
{
    for(int i = 0; i < SIZE; i++)
    {
        cout << endl;

        for(int j = 0; j < SIZE; j++)
            cout << setw(4) << mx[i][j];

        cout << endl;
   }
}

Согласитесь, что структура этого кода куда более понятна, чем предыдущего, т.к. четко можно просмотреть каждый блок и вложенные в него блоки. Рассмотрите внимательно, как в этой программе организована структура и придерживайтесь этих правил в своих программах. Приучайте себя к хорошему тону сразу, иначе потом сложно будет бороться с укоренившимися привычками.

P.S. Отступы делаются с помощью табуляции (клавиша TAB). По стандарту отступ равен 4 пробелам. Посмотреть и изменить настройки можно в настройках редактора вашей среды разработки.

2. Пожалуй, ко второму правилу отнесу тоже отступы, только уже не горизонтальные, а вертикальные отступы. Разницу между их отсутствием и присутствием также можно рассмотреть на примере предыдущих двух листингов программ. Скажу лишь то, что логические блоки нужно для ясности разделять одним вертикальным отступом (т.е. одной пустой строкой). К таким логическим блокам можно, к примеру, отнести блок подключения заголовочных файлов, блок объявления переменных, блоки операторов выбора и циклов, функции и так далее.

3. Со структурой кода разобрались. Теперь заглянем в саму программу. Первое, о чем хотелось бы сказать, это, конечно же, комментарии. В тех местах программы, где выполняются какие-либо сложные действия, нужно вставлять комментарии, чтобы вы сами же через время смогли вспомнить, как реализовали ту или иную часть алгоритма. Да и другим программистам, при просмотре вашего кода, все будет понятно. Также, если вы работаете в консоли, то нужно обязательно выводить подсказку для пользователя о том, что от него требуется и о том, что выводит программа.

4. Пробелы в коде. Сравните два кусочка кода ниже, и вы поймете о чем я хотел рассказать в этом пункте.

//печать массива
void printMatrix(int mx[][12],const int SIZE)
{
    for(int i=0;i<SIZE;i++)
    {
        cout<<endl;

        for(int j=0;j<SIZE;j++)
            cout<<setw(4)<<mx[i][j];

        cout<<endl;
   }
}

 

//печать массива
void printMatrix(int mx[][12], const int SIZE)
{
    for(int i = 0; i < SIZE; i++)
    {
        cout << endl;

        for(int j = 0; j < SIZE; j++)
            cout << setw(4) << mx[i][j];

        cout << endl;
   }
}

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

5. Этот пункт будет большим и важным. Здесь мы рассмотрим именование объектов программы (переменных, функций, классов, методов и т.д.).

Стиль именования

Все объекты программы должны быть названы обоснованными именами, говорящими о назначении того или иного объекта.

counter, increment - счетчик
name, lastName - имя, фамилия
phone - телефон
city - город

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

Неправильно - правильно

matrica - matrix
stroka - str
razmer - size
maksimum - maximum, max
parametr - value

Константы рекомендуется писать в верхнем регистре.

SIZE, POINT, BOOK

Для именования переменных нужно использовать существительные, а для именования функций глаголы (либо глагол + существительное), т.к. это действие. Пример функций

playSong()
printArray()
readString()

При именовании методов классов и функций, которые должны что-то возвращать, используют префикс get (получить). Для тех, которые устанавливают, используют set (установить)

getTime();
setTime();

Верблюжья нотация

Выше мы рассматривали простые имена объектов. Довольно часто нужно именовать объект посредством составных слов. В этом случае используют "верблюжью нотацию" (запись напоминает горбы верблюдов). В этом случае, несколько слов, либо их сокращений пишутся слитно без пробелов, но при этом каждое слово начинается с заглавной буквы. Ниже примеры

lastName
userName
copyText()
firstTimer
mySecondBook

Венгерская нотация

В основе венгерской нотации лежит добавление специальных префиксов в начале имени того или иного объекта. Эти префиксы обычно говорят о типе создаваемого объекта. Венгерская нотация не входит в стандарты языка, поэтому использовать ее или нет, это ваше личное дело. А я лишь кратко расскажу об основных префиксах

string sLastName;
int nBook, iMonth;
bool bState;
int* pCell, ptrRow;
class CWocker;
void vPrintMatrix();