¿Principios de diseño, mejores prácticas y patrones de diseño para C (o programación de procedimientos en general)? [cerrado]

91

¿Existen principios de diseño conocidos, mejores prácticas y patrones de diseño que se puedan seguir al diseñar un proyecto en C? ¿O principios de diseño útiles para la programación procedimental (imperativa) en general?

(Soy hijo de la 'generación orientada a objetos' y tengo que diseñar un gran proyecto en C por primera vez)

Dimi
fuente
1
Puede que le interesen las respuestas a esta pregunta: stackoverflow.com/questions/661307/…
mouviciel
7
Hice algunas investigaciones en Internet y en bibliotecas universitarias, antes de publicar mi pregunta, y definitivamente no me sentí abrumado por los libros sobre diseño de software para C.Le pregunto cuál es su favorito (sin hablar de libros C generales, sin hablar de convenciones de codificación como variables significativas nombres, pero sobre una mayor abstracción, nivel de arquitectura de software). Además, no estoy de acuerdo con su reproche de "depender de otras personas". ¿Quiere decir que cada programador debería averiguar por sí mismo las mejores prácticas y los buenos patrones de diseño? Esta es sin duda una pregunta sobre la que se debe utilizar la experiencia de otros.
Dimi
2
Lo siento, Dimi, no se trataba de ti en particular, y no fue muy claro. Este material solía transmitirse tanto por tradición oral como de cualquier otra manera: no había un conjunto nominal de "Patrones" oficiales, la respuesta de Jonathon era lo que encontraría en los libros, pero todos sabían sobre la ocultación de información. Parece que la tradición oral se está perdiendo y muchos programadores jóvenes piensan que OOP inventó la encapsulación y la separación. Esta comunidad parece tener menos sentido de su propia historia de lo que me gustaría ver. De ahí mi reconocimiento de que estoy en territorio de viejo gruñón.
dmckee --- ex-moderador gatito
1
No puedo compartir su vista retrospectiva ya que acabo de encontrar mis pies en el campo, pero acepto su sugerencia. Gracias por expresarse con mayor claridad, siempre de gran valor para llegar a leer la vista de una persona experimentada. Realmente aprecio tu contribución.
Dimi
El estándar de codificación SEI CERT C proporciona un buen conjunto de reglas y buenas prácticas comunes , así como cosas que debe intentar evitar.
Rami

Respuestas:

65

Ocultación de información: como lo propugna Parnas ( Software Fundamentals ).

Gestión cuidadosa de encabezados y visibilidad:

  • Todo en un archivo de origen que pueda ocultarse del mundo exterior debería estarlo; solo debe exponerse la interfaz externa documentada.
  • Todo lo que se expone se declara en un encabezado.
  • Ese encabezado se usa donde se necesita la funcionalidad (y donde está definida).
  • El encabezado es autónomo: cuando lo necesita, lo usa, y no tiene que preocuparse por 'qué otros encabezados también tengo que incluir' porque el encabezado garantiza que funciona al incluir todo lo que necesita para hacerlo trabajo.
  • El encabezado está autoprotegido, por lo que no importa si se incluye varias veces.

    #ifndef HEADER_H_INCLUDED
    #define HEADER_H_INCLUDED
    ...rest of header contents, including other #include lines if necessary
    #endif /* HEADER_H_INCLUDED */
  • Diseñe conjuntos de funciones para trabajar en 'objetos' (generalmente estructuras) y use esas funciones en lugar de hurgar en las entrañas de la estructura en el código que lo está usando. Piense en ello como una encapsulación autoimpuesta.

Jonathan Leffler
fuente
Buen punto, gracias, Jonathan. Los tipos de datos abstractos son otro buen ejemplo de ocultación de información con una clara separación de uso e implementación (interfaz externa conocida e implementación interna desconocida).
Dimi
23

Mis tres consejos:

  • Escribe pruebas unitarias. Le ayudarán a concentrarse en un diseño que se adapte a su problema a medida que avanza. Mucho mejor que confiar (únicamente) en el pensamiento premeditado.
  • Tenga un detector de fugas de memoria (hay todo tipo de bibliotecas) instalado y funcionando desde el primer día. Haga que esta biblioteca imprima todas las fugas tan pronto como finalice el programa o las pruebas. Esto le permitirá detectar una fuga tan pronto como la introduzca, lo que hará que su reparación sea mucho menos dolorosa.
  • Escriba el código OOP en C. No es tan difícil. Si bien es posible emular la anulación de métodos, le sugiero que comience con la emulación de objetos simples. Incluso este simple mecanismo puede brindarle un gran kilometraje.

He aquí un ejemplo:

typedef struct Vector {
  int size;
  int limit;
  int* ints; 
} Vector;

Vector* Vector_new() {
  Vector* res = (Vector*) malloc(sizeof(Vector));
  res->limit = 10;
  res->size = 0;
  res->ints = (int*) malloc(sizeof(int) * res.limit);

  return res;
}


void Vector_destroy(Vector* v) {
  free(v->ints);
  free(v);
}

void Vector_add(Vector* v, int n) {
  if(v->size == v->limit) {
    v->limit = v->limit * 2 + 10;
    v->ints = realloc(v->ints, v->limit);     
  }

  v->ints[v->size] = n;
  ++v->size;
}

int Vector_get(Vector* v, int index) {
  if(index >= 0 && index < v->size)
    return v->ints[index];

  assert false;
}
Itay Maman
fuente
Gracias, Itay. Seguiré tus consejos.
Dimi
1
4. No eches el resultado de malloc.
SS Anne
22

Existe un buen libro en línea gratuito, titulado Programación orientada a objetos con ANSI-C , que trata el tema de la escritura de código orientado a objetos en C. Una búsqueda en Google de "C orientada a objetos" también arroja una serie de otras buenas ejemplos y recursos.

Si su proyecto es crítico para la seguridad, MISRA-C es un buen conjunto de reglas. Está pensado principalmente para c incrustado, pero también puede ser útil en otras áreas.

Me considero un codificador OO y trabajo mucho con embedded-C. El mejor consejo que puedo dar, especialmente para proyectos grandes, es no exagerar. La creación de un marco OO completo sobre ANSI C puede ser muy tentador, pero requiere mucho tiempo y esfuerzo hacerlo bien. Cuanto más sofisticado sea, más tiempo dedicará a depurar su marco en lugar de trabajar en el proyecto real . Aborde la tarea con la cabeza despejada y una buena y sólida comprensión de YAGNI . ¡La mejor de las suertes!

e.James
fuente
Gracias, e.James. No quiero crear un marco orientado a objetos sobre ANSI C, pero busco principios de diseño de programación de procedimientos especiales y apropiados. La pista MISRA-C es muy útil, especialmente porque en realidad es un proyecto integrado. Voy a echarle un vistazo más de cerca.
Dimi
Ah, el placer de la C. incrustada. No olvides que tienes que declarar tus variables en la parte superior de tu función (o en la parte superior de cualquier { }bloque). Ese siempre me muerde una o dos veces:)
e.James
7

OOP es una metodología, no una tecnología. Así que mi primer consejo es dejar de pensar en ello como programación procedimental.

Para el punto de e.James, usted no quiere intentar recrear un lenguaje orientado a objetos o pretender que tiene las capacidades del mismo. Aún puede hacer todo lo correcto si se aferra a algunos principios simples:

  1. Pruebe todo.
  2. Encuentre lo que varía y encapsúlelo.
  3. Diseño de interfaces.

fuente