Если я продолжу писать больше кода, то будет время, когда мне будет трудно организовать код.
Это ваша проблема: выправьте организацию правильно, и стиль должен развиваться легче.
Не ждите, чтобы организовать свой код: держите ваш код организованным на ходу. Хотя язык не делает этого за вас, код все равно должен быть организован в модули с низкой связью и высокой связностью.
Эти модули затем естественно предоставляют пространство имен. Сократите имя модуля (если оно длинное) и добавьте к имени модуля префиксные функции, чтобы избежать коллизий.
На уровне отдельных идентификаторов они примерно в порядке возрастания субъективности:
- выбрать конвенцию и придерживаться ее
- например,
function_like_this(struct TypeLikeThis variable)
распространено
определенно избегайте венгерских обозначений (извините, JNL)
если вы не хотите использовать его так, как предполагалось изначально, что означает нотацию приложений Simonyi, а не ужасную версию системы
Почему? Я мог бы написать эссе об этом, но вместо этого я предлагаю вам прочитать эту статью Джоэла Спольски, а затем поохотиться еще немного, если вам интересно. Внизу есть ссылка на оригинальную статью Симони.
избегайте указателей typedefs, если они не являются действительно непрозрачными типами cookie - они только запутывают вещи
struct Type *ok;
typedef struct Type *TypePtr;
TypePtr yuck;
Что я подразумеваю под непрозрачным типом печенья ? Я имею в виду то, что используется внутри модуля (или библиотеки, или чего-то еще), которое должно быть передано клиентскому коду, но этот клиентский код не может использоваться напрямую. Он просто передает его обратно в библиотеку.
Например, библиотека базы данных может предоставлять такой интерфейс, как
/* Lots of buffering, IPC and metadata magic held in here.
No, you don't get to look inside. */
struct DBContextT;
/* In fact, you only ever get a pointer, so let's give it a nice name */
typedef struct DBContexT *DBContext;
DBContext db_allocate_context(/*maybe some optional flags?*/);
void db_release_context(DBContext);
int db_connect(DBContext, const char *connect);
int db_disconnect(DBContext);
int db_execute(DBContext, const char *sql);
Теперь контекст непрозрачен для клиентского кода, потому что вы не можете заглянуть внутрь. Вы просто передаете это обратно в библиотеку. Нечто подобное FILE
также непрозрачно, и целочисленный файловый дескриптор также является cookie , но не непрозрачен.
Примечание по дизайну
Я использовал фразу « слабая связь и высокая сплоченность» выше без объяснения причин, и я чувствую себя немного плохо по этому поводу. Вы можете найти его и, возможно, найти хорошие результаты, но я постараюсь кратко остановиться на нем (опять же, я мог бы написать эссе, но постараюсь не делать этого).
Библиотека DB, показанная выше, показывает слабую связь, потому что она предоставляет маленький интерфейс для внешнего мира. Скрывая детали своей реализации (частично с помощью непрозрачного трюка с cookie), он предотвращает зависимость кода клиента от этих деталей.
Представьте, что вместо непрозрачного cookie-файла мы объявляем структуру контекста, чтобы ее содержимое было видимым, включая дескриптор файла сокета для соединения TCP с базой данных. Если впоследствии мы изменим реализацию для поддержки использования сегмента общей памяти, когда БД работает на том же компьютере, клиент должен быть перекомпилирован, а не просто перекомпонован. Хуже того, клиент мог начать использовать файловый дескриптор, например, вызвать setsockopt
изменение размера буфера по умолчанию, и теперь ему также нужно изменить код. Все эти детали должны быть скрыты внутри нашего модуля, где это практически возможно, и это дает низкую связь между модулями.
В примере также показана высокая степень согласованности , поскольку все методы модуля связаны с одной и той же задачей (доступ к БД). Это означает, что только код, который должен знать о деталях реализации (то есть о содержимом нашего cookie), фактически имеет к ним доступ, что упрощает отладку.
Вы также можете видеть, что наличие одной задачи облегчало выбор префикса для группировки этих функций.
Теперь сказать, что этот пример хороший, легко (особенно потому, что он еще не закончен), но не сразу вам поможет. Хитрость заключается в том, чтобы следить за тем, как вы пишете и расширяете свой код, за функциями, которые выполняют сходные функции или работают с одними и теми же типами (которые могут быть кандидатами для своего собственного модуля), а также за функциями, которые выполняют множество отдельных вещей, которые Это действительно связано, и может быть кандидатами на разделение.