taker-specs

Документация для проекта taker

This project is maintained by taker-project

Общие замечания по поводу работы над проектом

Code-style

Авто-форматирование

Для форматирования кода следует использовать astyle со следущими параметрами командной строки:

astyle --style=java --indent=tab=4 --attach-namespaces --attach-classes --attach-extern-c --indent-switches --indent-namespaces --indent-preproc-block --indent-preproc-cond --indent-preproc-define --pad-oper --pad-comma --pad-header --unpad-paren --fill-empty-lines --align-pointer=name --align-reference=name --add-brackets --remove-comment-prefix --lineend=linux <source code>

Или проще:

astyle --options=.astylerc <source code>.

Файл опций .astylerc лежит в этом репозитории.

Конструкторы

Оформление конструктора класса должно выглядеть следующим образом:

Constructor::Constructor(int a, int b)
	: m_a(a), m_b(b) {
	// operators
}

Оператор switch

Оформление оператора switch должно выглядеть следующим образом:

switch (a) {
	case 1: {
		// operators
		break;
	}
	case 2: {
		// operators
		break;
	}
	...
	default: {
		// operators
	}
}

Наличие ветви default обязательно, ограждать случаи в switch фигурными скобками также обязательно.

Именование переменных

Следует избегать коротких или однобуквенных названий переменных и функций, а так же названий, которые можно трактовать различными способами.

Примеры плохих названий переменных: flag, x, cnt, num, ans, val, date, f.

Исключение: допустимо (но не рекомендуется) использование переменной i в качестве локальной переменной-счётчика простого цикла for. Например, допустимо использование таких переменных для простого чтения или вывода массивов. В случае, если тело цикла содержит несколько команд или ветвление, использования однобуквенных переменных следует избегать.

Названия полей, методов класса и функций должны писаться в lowerCamelCase: myLittleCamel.

Названия классов, пространств имен и типов должны писаться в CamelCase: MyBigCamel.

Названия полей в enum, констант, а также макросов (которые не рекомендуется использовать), нужно писать БОЛЬШИМИ_БУКВАМИ.

К названиям полей классов следует добавлять префикс m_: m_начинатьСБуквыMЧтоЗначитMember.

К названиям глобальных переменных стоит добавлять префикс g_: g_начинатьСБуквыGЧтоЗначитGlobal.

Названия переменных, содержащие цифры, лучше не использовать.

Исключение: в простейщих операторах (например, операторах сравнения), а также простейших функциях типа min, max допустимо использование переменных типа item1, item2.

Возможности C++

Для целочисленных типов лучше использовать int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, intptr_t, uintptr_t и size_t. Про int, long long и т. д. стоит забыть.

Директивы препроцессора #define и #pragma лучше избегать. #define хорошо использовать только для условной компиляции.

Писать using namespace std; не надо (особенно в заголовочных файлах).

Стоит избегать использования функций в стиле Си, вроде scanf, printf, malloc, free, gets и так далее.

Для прохода по контейнерам стоит использовать for each, например, так:

for (ItemType item: items) {
	// operators
}

Стоит активно использовать пространства имен, для разных частей системы— разные пространства имен.

На C++ можно писать код, полный трюков, однако так делать не стоит. Код должен быть максимально ясным и понятным. Не стоит делать несколько действий в одну строку. Например, вместо

while (a[i++] = --j);

стоит написать

while (j != 1) {
	--j;
	a[i] = j;
	++i;
}

Предпочитайте префиксный инкремент (++i вместо i++).

Для перечислений стоит использовать enum class вместо enum.

Не стоит использовать преобразования типов в стиле Си, используйте static_cast<T>.

Возможно, список будет пополняться.

Заголовочные файлы

Заголовочные файлы должны иметь расширение .hpp, а исходники C++— расширение .cpp. Заголовочные файлы следует называть в camelCase, например: headerFile.hpp.

В заголовочном файле должны содержаться следующие строки (пусть файл называется example/myHeader.hpp):

#ifndef EXAMPLE_MY_HEADER_HPP
#define EXAMPLE_MY_HEADER_HPP

// Здесь код

#endif

В начале каждого файла должен содержаться заголовок лицензии. Выглядит он следующим образом:

/*
  This file is part of Taker
  Copyright (C) <год> Taker Project Developers
  
  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
  
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

Ниже должен идти комментарий, который поясняет назначение файла.

Константы

Использование литералов в коде нежелательно. Исключения такие: разрешены числовые литералы 0, 1, -1. Все остальные литералы необходимо оформить в виде констант. Например, код

for (int i = 0; i < 12; i++) {
	if (values[i] > 4096) {
		return 42;
	}
}

можно переписать так:

const int valuesCount = 12;
const int maxValue = 4096;
const int statusBadValue = 42;

for (int i = 0; i < valuesCount; i++) {
	if (values[i] > maxValue) {
		return statusBadValue;
	}
}

Конечно, в реальном коде лучше всего дать наиболее осмысленные имена константам. statusBadValue здесь только для примера, гораздо лучше использование enum class для подобных целей.

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

Работа с git

Для работы над проектом будет использоваться git. Каждый должен работать в своей ветке, которые потом будут сливаться вместе. Коммитить напрямую в ветку master можно только в особых случаях (например, исправление мелкого бага в уже существующем коде, которое можно сделать за один небольшой коммит). Перед тем, как коммитить в master, лучше согласовать это.

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

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

Названия коммитов и pull-requestов должно быть осмысленное и отражать сделанные в них изменения.

Спецификации

Следовать спецификациям в этом репозитории обязательно. Если вы считаете, что какую-то часть этих спецификаций стоит изменить, стоит сначала сделать pull-request в этот репозиторий.

Может получиться и так, что спецификации описывают не все. Если какая-то часть кода реализует незадокументированные в спецификациях возможности, стоит добавить информацию о них сюда.

Если часть спецификации сложна в реализации или оставлена на потом, стоит оставить TODO-комментарий в коде, чтобы эту часть спецификации можно было реализовать потом.