Si sigo escribiendo más código, habrá un momento en que me será difícil organizar el código.
Este es su problema: haga que la organización sea correcta y el estilo debería fluir más fácilmente.
No espere para organizar su código: mantenga su código organizado a medida que avanza. Aunque el lenguaje no lo hace por usted, el código aún debe organizarse en módulos con bajo acoplamiento y alta cohesión.
Estos módulos proporcionan naturalmente un espacio de nombres. Abrevie el nombre del módulo (si es largo) y prefije los nombres de las funciones con su módulo para evitar colisiones.
A nivel de identificadores individuales, estos están más o menos en orden creciente de subjetividad:
- elige una convención y síguela
- por ejemplo,
function_like_this(struct TypeLikeThis variable)es común
definitivamente evite la notación húngara (lo siento JNL)
a menos que esté dispuesto a usarlo como se pretendía originalmente, lo que significa la notación de aplicaciones de Simonyi en lugar de la terrible versión del sistema
¿Por qué? Podría escribir un ensayo sobre esto, pero en su lugar te sugiero que leas este artículo de Joel Spolsky, y luego busques un poco más si estás interesado. Hay un enlace al artículo original de Simonyi en la parte inferior.
evite los tipos de puntero a menos que sean tipos de cookies genuinamente opacos; solo confunden cosas
struct Type *ok;
typedef struct Type *TypePtr;
TypePtr yuck;
¿Qué quiero decir con un tipo de cookie opaco ? Me refiero a algo usado dentro de un módulo (o biblioteca, o lo que sea) que debe pasarse al código del cliente, pero ese código del cliente no puede usarse directamente. Simplemente lo devuelve a la biblioteca.
Por ejemplo, una biblioteca de base de datos podría exponer una interfaz 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);
Ahora, el contexto es opaco al código del cliente, porque no puede mirar dentro. Simplemente devuélvelo a la biblioteca. Algo así FILEtambién es opaco, y un descriptor de archivo entero también es una cookie , pero no es opaco.
Una nota sobre diseño
Utilicé la frase bajo acoplamiento y alta cohesión arriba sin explicación, y me siento un poco mal por eso. Puede buscarlo y probablemente encuentre algunos buenos resultados, pero intentaré abordarlo brevemente (nuevamente, podría escribir un ensayo pero intentaré no hacerlo).
La biblioteca de DB esbozada anteriormente muestra un bajo acoplamiento porque expone una pequeña interfaz al mundo exterior. Al ocultar sus detalles de implementación (en parte con el truco de las cookies opacas), evita que el código del cliente dependa de esos detalles.
Imagine en lugar de la cookie opaca, declaramos la estructura de contexto para que su contenido sea visible, y eso incluye un descriptor de archivo de socket para una conexión TCP a la base de datos. Si posteriormente cambiamos la implementación para admitir el uso de un segmento de memoria compartida cuando la base de datos se ejecuta en la misma máquina, el cliente debe volver a compilarse en lugar de volver a vincularse. Peor aún, el cliente podría haber comenzado a usar el descriptor de archivo, por ejemplo, llamando setsockoptpara cambiar el tamaño predeterminado del búfer, y ahora también necesita un cambio de código. Todos estos detalles deben ocultarse dentro de nuestro módulo cuando sea práctico, y esto proporciona un bajo acoplamiento entre módulos.
El ejemplo también muestra una alta cohesión , ya que todos los métodos en el módulo están relacionados con la misma tarea (acceso a la base de datos). Esto significa que solo el código que necesita conocer los detalles de implementación (es decir, el contenido de nuestra cookie) realmente tiene acceso a ellos, lo que simplifica la depuración.
También puede ver que tener una sola preocupación facilitaba la elección de un prefijo para agrupar estas funciones.
Ahora, decir que este ejemplo es bueno es fácil (especialmente porque ni siquiera está completo), pero no lo ayuda de inmediato. El truco es observar, a medida que escribe y extiende su código, las funciones que hacen cosas similares u operan en los mismos tipos (que podrían ser candidatos para su propio módulo), y también las funciones que hacen muchas cosas separadas que no son No está realmente relacionado y podría ser candidato para separarse.