Якщо я продовжую писати більше коду, тоді настане час, коли мені буде складно організувати код.
У цьому ваша проблема: виправте організацію, і стиль повинен протікати легше.
Не чекайте, щоб упорядкувати свій код: тримайте код впорядкованому під час руху. Хоча мова це не робить для вас, код все одно повинен бути організований в модулі з низькою сполученістю і високою згуртованістю.
Ці модулі, природно, забезпечують простір імен. Скоротіть назву модуля (якщо він довгий) та вкажіть назви функцій префікса їх модулем, щоб уникнути зіткнень.
На рівні індивідуальних ідентифікаторів вони приблизно в порядку зростання суб'єктивності:
- виберіть умову і дотримуйтесь її
- наприклад,
function_like_this(struct TypeLikeThis variable)
є загальним
обов'язково уникайте угорських позначень (вибачте JNL)
якщо ви не бажаєте використовувати його як було призначено спочатку, це означає позначення додатків Сімоні, а не жахливу версію системи
Чому? Я можу написати про це есе, але замість цього запропоную вам прочитати цю статтю Джоела Спольського, а потім полюйте ще трохи, якщо вам цікаво. Внизу є посилання на оригінальний папір Сімоні.
уникайте типів покажчиків, якщо вони не є справді непрозорими типами файлів cookie - вони лише плутають речі
struct Type *ok;
typedef struct Type *TypePtr;
TypePtr yuck;
Що я маю на увазі під непрозорим типом cookie ? Я маю на увазі щось, що використовується у модулі (або бібліотеці чи будь-якому іншому), що має бути передано коду клієнта, але цей клієнтський код не може використовуватись безпосередньо. Він просто передає його назад до бібліотеки.
Наприклад, бібліотека баз даних може відкрити подібний інтерфейс
/* 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 , але не є непрозорим.
Примітка про дизайн
Я використовував вище фразу " низька зв'язок" і "висока згуртованість" , і мені це дуже погано. Ви можете шукати його і, ймовірно, знайти якісь хороші результати, але я спробую коротко розглянути його (знову ж, я можу написати твір, але намагаюся цього не робити).
Бібліотека БД, накреслена вище, демонструє низьке з'єднання, оскільки вона відкриває невеликий інтерфейс для зовнішнього світу. Приховуючи дані про його реалізацію (частково з непрозорим фокусом cookie), вона не дозволяє коду клієнта залежати від цих деталей.
Уявіть, що замість непрозорого файлу cookie ми оголосимо структуру контексту, щоб її вміст був видно, і він включає дескриптор файлу сокета для підключення TCP до бази даних. Якщо ми згодом змінимо реалізацію на підтримку використання сегмента спільної пам’яті, коли БД працює на одній машині, клієнт повинен бути перекомпільований, а не просто повторний зв’язок. Ще гірше, що клієнт міг почати використовувати дескриптор файлів, наприклад, закликаючи setsockopt
змінити розмір буфера за замовчуванням, і тепер він також потребує зміни коду. Усі ці деталі повинні бути заховані всередині нашого модуля, де це практично, і це забезпечує низьке з'єднання між модулями.
Приклад також показує високу згуртованість , оскільки всі методи в модулі стосуються одного завдання (доступ до БД). Це означає, що лише код, який потрібно знати про деталі реалізації (тобто вміст нашого файлу cookie), насправді має доступ до них, що спрощує налагодження.
Ви також можете бачити, що, маючи одну проблему, було легко вибрати префікс, щоб згрупувати ці функції разом.
Тепер сказати, що цей приклад хороший - це легко (тим більше, що він навіть не є повним), але не одразу вам допомагає. Трюк полягає в тому, щоб спостерігати за тим, як ви пишете та розширюєте свій код, на функції, які роблять подібні речі або працюють на тих же типах (які можуть бути кандидатами для власного модуля), а також на функції, які роблять багато окремих речей, які не є ' t по-справжньому пов'язані і можуть бути кандидатами на розкол.