Se eu continuar escrevendo mais código, haverá um momento em que será difícil para mim organizar o código.
Esse é o seu problema: acerte a organização e o estilo deve fluir mais facilmente.
Não espere para organizar seu código: mantenha seu código organizado à medida que avança. Embora a linguagem não faça isso por você, o código ainda deve ser organizado em módulos com baixo acoplamento e alta coesão.
Esses módulos, naturalmente, fornecem um espaço para nome. Abrevie o nome do módulo (se for longo) e prefixe os nomes das funções com seu módulo para evitar colisões.
No nível dos identificadores individuais, eles estão aproximadamente em ordem crescente de subjetividade:
- escolha uma convenção e fique com ela
- por exemplo,
function_like_this(struct TypeLikeThis variable)
é comum
definitivamente evitar a notação húngara (desculpe JNL)
a menos que você esteja disposto a usá-lo como pretendido originalmente, o que significa a notação de aplicativos de Simonyi em vez da terrível versão de sistemas
Por quê? Eu poderia escrever um ensaio sobre isso, mas, em vez disso, sugiro que você leia este artigo de Joel Spolsky e, em seguida, procure um pouco mais, se estiver interessado. Há um link para o artigo original de Simonyi na parte inferior.
evite typedefs de ponteiro, a menos que sejam tipos de cookies genuinamente opacos - eles apenas confundem as coisas
struct Type *ok;
typedef struct Type *TypePtr;
TypePtr yuck;
O que quero dizer com um tipo de cookie opaco ? Quero dizer algo usado dentro de um módulo (ou biblioteca, ou o que seja) que deve ser passado para o código do cliente, mas esse código do cliente não pode ser usado diretamente. Apenas passa de volta para a biblioteca.
Por exemplo, uma biblioteca de banco de dados pode expor uma interface como
/* 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);
Agora, o contexto é opaco ao código do cliente, porque você não pode olhar para dentro. Você acabou de devolvê-lo à biblioteca. Algo como FILE
também é opaco, e um descritor de arquivo inteiro também é um cookie , mas não é opaco.
Uma nota sobre design
Usei a frase baixo acoplamento e alta coesão acima, sem explicação, e me sinto um pouco mal com isso. Você pode procurá-lo e provavelmente encontrar bons resultados, mas tentarei abordar brevemente (novamente, eu poderia escrever um ensaio, mas tentarei não).
A biblioteca do DB esboçada acima mostra baixo acoplamento porque expõe uma pequena interface para o mundo externo. Ocultando seus detalhes de implementação (em parte com o truque de cookie opaco), impede que o código do cliente dependa desses detalhes.
Imagine, em vez do cookie opaco, declaramos a estrutura do contexto para que seu conteúdo seja visível, e isso inclui um descritor de arquivo de soquete para uma conexão TCP ao banco de dados. Se posteriormente mudarmos a implementação para oferecer suporte ao uso de um segmento de memória compartilhada quando o banco de dados estiver em execução na mesma máquina, o cliente precisará ser recompilado em vez de apenas vinculado novamente. Pior ainda, o cliente poderia ter começado a usar o descritor de arquivo, por exemplo, chamando setsockopt
para alterar o tamanho padrão do buffer, e agora também precisa de uma alteração no código. Todos esses detalhes devem estar ocultos dentro do nosso módulo, sempre que possível, e isso proporciona baixo acoplamento entre os módulos.
O exemplo também mostra alta coesão , pois todos os métodos no módulo estão relacionados à mesma tarefa (acesso ao banco de dados). Isso significa que apenas o código que precisa saber sobre os detalhes da implementação (ou seja, o conteúdo do nosso cookie) realmente tem acesso a eles, o que simplifica a depuração.
Você também pode ver que ter uma única preocupação facilitou a escolha de um prefixo para agrupar essas funções.
Agora, dizer que este exemplo é bom é fácil (especialmente porque nem sequer está completo), mas não ajuda imediatamente. O truque é observar, enquanto você escreve e estende seu código, para funções que fazem coisas semelhantes ou operam nos mesmos tipos (que podem ser candidatos ao seu próprio módulo) e também para funções que fazem muitas coisas separadas que não são ' Não está realmente relacionado e pode ser candidato à divisão.