Cómo hacer que una base de código grande sea más fácil de entender

104

Supongamos que estoy desarrollando un proyecto relativamente grande. Ya he documentado todas mis clases y funciones con Doxygen, sin embargo, tuve la idea de poner "notas de programador" en cada archivo de código fuente.

La idea detrás de esto es explicar en términos simples cómo funciona una clase específica (y no solo por qué, como lo hacen la mayoría de los comentarios). En otras palabras, darles a otros programadores una visión diferente de cómo funciona una clase.

Por ejemplo:

/*
 * PROGRAMMER'S NOTES:
 *
 * As stated in the documentation, the GamepadManager class 
 * reads joystick joystick input using SDL and 'parses' SDL events to
 * Qt signals.
 *
 * Most of the code here is about goofing around the joystick mappings.
 * We want to avoid having different joystick behaviours between
 * operating systems to have a more integrated user experience, since
 * we don't want team members to have a bad surprise while
 * driving their robots with different laptops.
 *
 * Unfortunately, we cannot use SDL's GamepadAPI because the robots
 * are interested in getting the button/axes numbers, not the "A" or
 * "X" button.
 *
 * To get around this issue, we created a INI file for the most common 
 * controllers that maps each joystick button/axis to the "standard" 
 * buttons and axes used by most teams. 
 *
 * We choose to use INI files because we can safely use QSettings
 * to read its values and we don't have to worry about having to use
 * third-party tools to read other formats.
 */

¿Sería esta una buena manera de hacer que un proyecto grande sea más fácil para que los nuevos programadores / contribuyentes entiendan cómo funciona? Además de mantener un estilo de codificación coherente y una organización de directorio 'estándar', ¿existen 'estándares' o recomendaciones para estos casos?

Alex Spataru
fuente
32
Diablos no. Si su código es ilegible, la documentación no ayudará.
Telastyn
35
@jeffo: el problema es que tomarse el tiempo para hacerlo puede suceder una vez. El tiempo para mantener el código legible ocurre con el tiempo. He estado en lugares con este tipo de documentación, cuando el proyecto era joven o cuando Joe el Perfeccionista todavía estaba en el equipo. Luego fue abandonado y los comentarios persistieron, ya no eran precisos.
Telastyn
25
Al menos en un nivel superior, una descripción en prosa fuera de código de lo que hace un proyecto, cómo funciona y qué compensaciones se han hecho en la arquitectura es invaluable. Este tipo de documento es una lectura obligada para un recién llegado antes de hacer un recorrido por el código. Hay mucha mierda de mi metodología es demasiado radical para los docs-dude alrededor de la red, y si bien es cierto que un documento de arco inicial y un documento de arco en evolución no se alinearán, es necesaria una descripción en prosa para que cualquiera pueda comprender rápidamente una base de código grande y no trivial. Aquí hay un ejemplo (pobre): zxq9.com/erlmud/html/001-002_architecture.html
zxq9
11
@Telastyn: Esto no tiene nada que ver con si el código es legible o no (y espero que lo sea). Documentar la lógica del diseño es absolutamente importante.
ligereza corre en órbita el
77
@Telastyn: Sí, tal vez. Personalmente lo escribiría en un documento independiente. Pero los bloques de comentarios en la parte superior de los archivos fuente no son tan malos.
ligereza corre en órbita el

Respuestas:

139

Esto es asombroso Deseo que más desarrolladores de software se tomen el tiempo y el esfuerzo para hacer esto. Eso:

  • Establece en inglés simple lo que hace la clase (es decir, es responsabilidad),
  • Proporciona información complementaria útil sobre el código sin repetir textualmente lo que el código ya dice,
  • Describe algunas de las decisiones de diseño y por qué se tomaron, y
  • Destaca algunas de las trampas que pueden ocurrirle a la próxima persona que lea su código.

Por desgracia, muchos programadores caen en el campo de "si el código está escrito correctamente, no debería tener que documentarse". No es verdad. Hay muchas relaciones implícitas entre clases de código, métodos, módulos y otros artefactos que no son obvios simplemente leyendo el código en sí.

Un codificador experimentado puede diseñar cuidadosamente un diseño que tenga una arquitectura clara y fácil de entender que sea obvia sin documentación. Pero, ¿cuántos programas como ese has visto realmente?

Robert Harvey
fuente
15
Y por qué el "Mes del hombre mítico" se convierte en una profecía autocumplida, nadie se tomó el tiempo para escribir todo esto para el nuevo desarrollador cuando estaba fresco en su mente y el proyecto no se retrasó.
JeffO
3
Estoy de acuerdo con cada punto que haces aquí. No me gusta el término que el OP utilizó en su publicación how a class works. Esto cambia con el tiempo y el mantenimiento. Aunque mi equipo no pone lo anterior en la fuente. Mantenemos un wiki con decisiones y copiamos la discusión del canal flojo sobre decisiones de diseño sin procesar en un documento (Proporcionamos un enlace desde el resumen y la conclusión de la decisión hasta las notas sin procesar para que no tengamos que volver a analizar las decisiones antiguas). Todo bien hecho en github (por lo que está todo en un solo lugar).
Martin York
1
Mi único problema es aplicar esto globalmente. Esta clase es lo suficientemente compleja, con ciertas trampas disponibles, claramente es realmente útil (aunque todavía terminas lidiando con Comentario Rot). Cuando una clase es más obvia, el comentario puede ser un poco superfluo.
deworde
1
"Un codificador experimentado puede elaborar cuidadosamente un diseño que tenga una arquitectura clara y fácil de entender que sea obvia sin documentación. Pero cuántos programas como ese has visto realmente" Si bien esto es cierto, la calidad de la documentación nunca es mejor que la calidad de el código. El código bien diseñado tiende a tener una buena documentación, si no tiene sentido. El código mal
diseñado
3
Estoy totalmente de acuerdo con esta respuesta, y si encontrara algo como el ejemplo del OP en el código, estaría muy feliz. Solo una adición: considere agregar una fecha a su comentario, solo para dar una pista a los lectores eventuales sobre la frescura de la descripción, y actualícela cada vez que actualice el texto.
Svalorzen
36

La clave para trabajar con una base de código grande es no tener que leer la base de código completa para hacer un cambio. Para permitir que un programador encuentre rápidamente el código que está buscando, el código debe estar organizado y la organización debe ser aparente. Es decir, cada unidad lógica en el código, desde el ejecutable, la biblioteca, el espacio de nombres, hasta la clase individual debe tener una responsabilidad claramente aparente. Por lo tanto, no solo documentaría los archivos fuente, sino también los directorios en los que residen.

Las notas de su programador también brindan antecedentes sobre las decisiones de diseño. Si bien esta puede ser información valiosa, la separaría de la declaración de responsabilidad (para que el lector pueda elegir si quiere leer sobre la responsabilidad de la clase o su lógica de diseño) y acercarla a la fuente que describe como sea posible, para maximizar la posibilidad de que la documentación se actualice cuando el código es (la documentación solo es útil si podemos confiar en su precisión; ¡la documentación obsoleta puede ser peor que ninguna!).

Dicho esto, la documentación debe permanecer SECA, es decir, no repetir información que podría haberse expresado en código o que ya se describió en otra parte (frases como "como dice la documentación" son una señal de advertencia). En particular, los futuros mantenedores solo serán competentes en el lenguaje de programación del proyecto, ya que están en inglés; parafrasear la implementación en los comentarios (que veo con demasiada frecuencia cuando la gente está orgullosa de su documentación) no tiene ningún beneficio, y es probable que difiera de la implementación, en particular si la documentación no está cerca del código que describe.

Finalmente, la estructura de la documentación debe estandarizarse en todo el proyecto para que todos puedan encontrarla (es un desastre real de documentos de Peter en el rastreador de errores, Sue en la wiki, Alan en el archivo Léame y John en el código fuente ...) .

meriton - en huelga
fuente
Su primera oración es exactamente cómo veo esto. Las bases de código grandes se deben componer como un número de componentes más pequeños donde un nuevo programador puede cambiar uno de manera confiable sin poner en peligro ninguno de los otros.
Jon Chesterfield
1
muévalo lo más cerca posible de la fuente que describe, para maximizar la posibilidad de que la documentación se actualice cuando el código lo esté . Esta es una experiencia valiosa.
laike9m
¡SECO como guía para la documentación es un muy buen punto! Eso establece automáticamente el enfoque correcto y prohíbe los famosos comentarios "// incrementar x en 1".
Hans-Peter Störr
13

No estaría de acuerdo con que este es un enfoque muy bueno, principalmente debido a

  1. Cuando refactoriza su proyecto, mueve los métodos, la documentación se rompe.

  2. Si la documentación no se actualiza correctamente, generará más confusión que ayuda para comprender el código.

Si tiene pruebas unitarias para cada método / pruebas de integración para cada módulo, sería una auto documentación más fácil de mantener y más fácil de entender en comparación con los comentarios de código.

Sí, tener una estructura de directorios adecuada definitivamente va a ayudar.

Pelican de bajo vuelo
fuente
+1 para las pruebas es la mejor manera de entender una base de código. Las pruebas unitarias, las pruebas de integración, las pruebas de aceptación cuentan la historia sobre cómo se supone que debe funcionar la aplicación y cómo se supone que debe usarse.
BZink
7

Personalmente, soy fanático de un documento de diseño de alto nivel, preferiblemente escrito ANTES de cualquier código, que brinde una descripción general del diseño y una lista de clases y recursos. Un diseño de arriba hacia abajo simplifica enormemente las cosas: el suyo podría ser "motor de juego -> hardware -> controladores -> joystick"; por lo tanto, un nuevo programador le dijo a "arreglar el botón 'a' en el controlador 'xyz" al menos sabría dónde comenzar a buscar.

Demasiados lenguajes modernos tienden a dividir el código en cientos de archivos pequeños, por lo que solo encontrar el archivo correcto puede ser un desafío incluso en un proyecto moderado.

DWalker
fuente
16
Hace 20 años, todo mi código estaba en un archivo enorme. Ahora está en miles de archivos pequeños y archivos de prueba. Hay una buena razón para esto y refleja 20 años de desarrollo de software (el ecosistema general, no mi conocimiento). Waaay demasiado tiempo para un comentario sin embargo.
Michael Durrant
44
ah, el viejo método de la cascada de escribir una sola, completa, inmutable, Verdad antes de que la codificación comience y hace que sea imposible desviarse en la implementación de dicha Verdad.
Jwenting
2
@jwenting: No tienes que llevarlo tan lejos. Pero aún así es bueno tener una idea de lo que está construyendo.
Robert Harvey
1
Ciertamente, sin la advertencia de cómo desglosar esto correctamente y dónde romper las reglas, rápidamente tendrá un documento que está desactualizado o es una piedra de molino. "Necesito agregar una nueva clase; ¡a Documanto, el Behemoth que consume tiempo!"
deworde
2
@deworde: lo leí como "demasiado vago para mantener la documentación".
Robert Harvey
6

Si la base del código es grande, trato de proporcionar un documento de diseño que mapee los elementos clave de su diseño y la implementación . La intención aquí no es detallar ninguna de las clases utilizadas, sino proporcionar una clave para el código y el pensamiento que se incluyó en el diseño. Da un contexto general al sistema, sus componentes y la aplicación del mismo.

Las cosas para incluir en el documento de diseño son;

  • Arquitectura de la aplicación
  • Estructura de código lógico
  • Flujos de datos
  • Patrones clave utilizados y la motivación detrás de su uso.
  • Estructura fuente de código
  • Cómo construirlo (esto ofrece información sobre las dependencias implícitas y la estructura del código fuente físico)

A continuación, se debe completar la documentación de las clases y las funciones / métodos, según corresponda . En particular la API pública; debe quedar claro cuáles son los siguientes en cada caso;

  • Condiciones previas
  • Efectos
  • Invariantes
  • Condiciones de excepción (tiros)
Niall
fuente
+1 Mejor que describir cada clase, ya que eso se desactualizará mucho más rápido que un diseño general.
Lode
4

La regla más importante que he encontrado para facilitar que los nuevos desarrolladores entiendan que una base de código es que el acuerdo perfecto es costoso.

Si los nuevos desarrolladores deben comprender perfectamente el sistema en el que están trabajando, evita todas las oportunidades de aprendizaje en el trabajo. Creo que las notas del programador son un excelente comienzo, pero iría más lejos. Intente escribir un código que, si se aborda de nuevo, permitiría a un desarrollador averiguar qué están haciendo sobre la marcha, en lugar de exigirles que aprendan antes de hacerlo. Pequeñas cosas como afirmaciones para casos que usted sabe que nunca pueden ocurrir, junto con comentarios que explican por qué la afirmación es válida, hacen mucho. También lo hace escribir código que falla con gracia en lugar de segfaular si haces algo mal.

Cort Ammon
fuente
Mi regla es que los comentarios deben ser sobre POR QUÉ , no CÓMO . El código describe CÓMO.
user11393
3

¡He visto clases grandes con documentación, y después de leer la documentación no tengo ni idea de para qué se supone que esta clase es buena y por qué alguien la usaría! Y al mismo tiempo, necesitaba algo de funcionalidad y estaba absolutamente seguro de que debía haber una clase para manejarlo, y no podía encontrarlo en ninguna parte, porque no había documentación que me llevara de lo que necesitaba a la clase. haciéndolo.

Entonces, lo primero que querría en la documentación son solo unas pocas oraciones sobre lo que hace una clase y por qué me gustaría usarla. Los comentarios en la pregunta original lo están haciendo bastante bien en ese sentido. Después de leer estos comentarios, si tuviera un joystick que no funciona bien porque no puedo interpretar los valores que ofrece, sabría qué código verificar.

gnasher729
fuente
0

Similar a lo que dijo @meriton, divida el código en componentes separados. Aún mejor, descomponga la base de código en paquetes separados (JAR, gemas, huevos, lo que sea) para que quede aún más claro cómo se separan los componentes. Si hay un error, un desarrollador solo necesita encontrar el paquete donde está el error y (con suerte) solo solucionarlo allí. Sin mencionar que es más fácil hacer pruebas unitarias y aprovechar la administración de dependencias.

Otra solución: hacer la base de código más pequeña. Cuanto menos código haya, más fácil será de entender. Refactorice el código no utilizado o duplicado. Utiliza técnicas de programación declarativa . Esto requiere esfuerzo, por supuesto, y a menudo no es posible o práctico. Pero es un objetivo digno. Como Jeff Atwood ha escrito: El mejor código no es ningún código

Sam Jones
fuente
-1

Para sistemas complejos, puede valer la pena no solo documentar cada archivo, sino también sus interacciones y jerarquía, y cómo se estructura el programa y por qué.

Por ejemplo, un motor de juego suele ser bastante complejo y es difícil decidir qué se llama después de cientos de capas de abstracción. Puede valer la pena crear un archivo como "Architecture.txt" para explicar cómo y por qué está estructurado el código de esta manera, y por qué existe esa capa de abstracción de aspecto inútil allí.

akaltar
fuente
-7

Esto puede deberse en parte a que es difícil para un solo programador escribirlo, ya que cada individuo comprende solo su parte del proyecto.

A veces puede obtener esta información de las notas del administrador del proyecto, pero eso es todo lo que obtendrá, ya que rara vez reescribirán sus notas en este formato.

Ilqar Rasulov
fuente
77
Si observa Github, encontrará muchos proyectos que tienen este tipo de nota en un archivo README.md. Se ha convertido en parte de la cultura de git en general y los proyectos de JavaScript en particular para la mayoría de las personas no usarán una biblioteca que no tenga este tipo de documentación de alto nivel. Por lo tanto, no es cierto que "ningún programador lo escriba", ya que solo necesita mirar algo como jQuery o socket.io y encontrar programadores que escriban esas cosas. También se ha convertido en una cultura que los archivos README que no son precisos generan informes de errores.
slebetman
1
Esto no parece responder a la pregunta, que buscaba razones por las cuales el estilo de documentación propuesto funcionaría o no, y también para los estándares de documentación.
user52889
55
Si tiene un equipo de programadores trabajando en un producto, y cada programador solo comprende el código específico en el que trabajaron, entonces su equipo no solo es increíblemente disfuncional con un factor de bus absurdo, sino que uno cuestiona la calidad del código. ¿Cómo se integra el código en un producto sin comprender el resto del código en el mismo sistema?
ligereza corre en órbita el