Se continuo a scrivere più codice, ci sarà un momento in cui sarà difficile organizzare il codice.
Questo è il tuo problema: ottenere l'organizzazione giusta e lo stile dovrebbe fluire più facilmente.
Non aspettare per organizzare il tuo codice: mantieni il tuo codice organizzato man mano che procedi. Sebbene la lingua non lo faccia per te, il codice dovrebbe comunque essere organizzato in moduli con basso accoppiamento e alta coesione.
Questi moduli forniscono quindi naturalmente uno spazio dei nomi. Abbrevia il nome del modulo (se è lungo) e prefiggi i nomi delle funzioni con il loro modulo per evitare collisioni.
A livello di singoli identificatori, questi sono all'incirca in ordine crescente di soggettività:
- scegli una convenzione e mantienila
- ad esempio,
function_like_this(struct TypeLikeThis variable)
è comune
evitare assolutamente la notazione ungherese (scusate JNL)
a meno che tu non sia disposto a usarlo come previsto originariamente, il che significa la notazione di app di Simonyi piuttosto che la terribile versione dei sistemi
Perché? Potrei scrivere un saggio a riguardo, ma suggerirò invece di leggere questo articolo di Joel Spolsky, e poi di cercare ancora un po 'se sei interessato. C'è un link al documento originale di Simonyi in fondo.
evitare i typedef dei puntatori a meno che non siano tipi di cookie veramente opachi - confondono solo le cose
struct Type *ok;
typedef struct Type *TypePtr;
TypePtr yuck;
Cosa intendo per tipo di cookie opaco ? Intendo qualcosa usato all'interno di un modulo (o libreria, o qualsiasi altra cosa) che deve essere passato al codice client, ma quel codice client non può essere usato direttamente. Lo restituisce alla libreria.
Ad esempio, una libreria di database potrebbe esporre un'interfaccia simile
/* 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);
Ora, il contesto è opaco per il codice client, perché non puoi guardarti dentro. Lo passi di nuovo in biblioteca. Qualcosa di simile FILE
è anche opaco e un descrittore di file intero è anche un cookie , ma non è opaco.
Una nota sul design
Ho usato la frase accoppiamento basso e alta coesione sopra senza spiegazioni, e mi sento un po 'male per questo. Puoi cercarlo e probabilmente trovare dei buoni risultati, ma proverò ad affrontarlo brevemente (di nuovo, potrei scrivere un saggio ma cercherò di non farlo).
La libreria DB di cui sopra mostra un accoppiamento basso perché espone una piccola interfaccia al mondo esterno. Nascondendo i suoi dettagli di implementazione (in parte con il trucco del cookie opaco), impedisce al codice client di dipendere da tali dettagli.
Immagina invece del cookie opaco, dichiariamo la struttura del contesto in modo che il suo contenuto sia visibile e che includa un descrittore di file socket per una connessione TCP al database. Se successivamente si modifica l'implementazione per supportare l'utilizzo di un segmento di memoria condivisa quando il DB è in esecuzione sullo stesso computer, è necessario ricompilare il client anziché ricollegarlo. Ancora peggio, il client avrebbe potuto iniziare a utilizzare il descrittore di file, ad esempio chiamando setsockopt
per modificare la dimensione del buffer predefinita e ora ha bisogno anche di una modifica del codice. Tutti questi dettagli dovrebbero essere nascosti all'interno del nostro modulo laddove possibile, e ciò garantisce un basso accoppiamento tra i moduli.
L'esempio mostra anche un'elevata coesione , in quanto tutti i metodi nel modulo riguardano lo stesso compito (accesso al DB). Ciò significa che solo il codice che deve conoscere i dettagli di implementazione (ovvero i contenuti dei nostri cookie) può effettivamente accedervi, il che semplifica il debug.
Puoi anche vedere che avere una sola preoccupazione ha reso facile scegliere un prefisso per raggruppare queste funzioni.
Ora, dire che questo esempio è buono è facile (soprattutto perché non è nemmeno completo), ma non ti aiuta immediatamente. Il trucco è guardare, mentre scrivi ed estendi il tuo codice, per funzioni che fanno cose simili o operano sugli stessi tipi (che potrebbero essere candidati per il proprio modulo), e anche per funzioni che fanno molte cose separate che non sono " Sono davvero imparentati e potrebbero essere candidati alla scissione.