Codificación de estilos cuando se usan varias bibliotecas dispares

9

Estoy trabajando en un código C ++ que usa varias bibliotecas, incluidas algunas bibliotecas C, que tienen diferentes estilos de codificación. Será de código abierto una vez que llegue a una etapa utilizable. ¿Qué causaría la menor confusión para un colaborador a corto plazo que revisa el código para corregir un error o agregar una función?

  • Tenga un estilo de codificación coherente en toda la aplicación, incluso si ocasionalmente no coincide con el estilo de codificación típico de las bibliotecas utilizadas.
  • Cuando una biblioteca se usa mucho en un determinado módulo, cumpla con el estilo de codificación típico de esa biblioteca (es decir, el estilo de codificación utilizado en el propio código y documentación de la biblioteca) en ese módulo.

Mi opinión es que esto último facilitará a los expertos en esa biblioteca en particular hacer contribuciones únicas y facilitará la incorporación de código tutorial / ejemplo durante el desarrollo. Sin embargo, también hace que el estilo de codificación sea inconsistente en toda la aplicación. ¿Cuáles son los pros y los contras de cada enfoque?

Karl Bielefeldt
fuente
44
¿Sería posible evitar este problema envolviendo todas las bibliotecas en sus propias abstracciones personalizadas? Su propio código y abstracciones podrían seguir un único estilo de codificación.
MetaFight
Mucho de lo que estoy haciendo es abstraer esas bibliotecas. La pregunta es qué estilo de codificación usar dentro de la abstracción.
Karl Bielefeldt
66
Ah No soy un experto aquí, pero parece que sería mejor usar la convención de la biblioteca en sí. Usar una convención no coincidente suena como una pesadilla de mantenimiento. Y siempre que el estilo de la biblioteca esté contenido en la clase / módulo que lo abstrae, supongo que estaría bien. Una vez más, no soy un profesional aquí, pero esto parece un buen equilibrio que le garantiza un mantenimiento más fácil en sus abstracciones y también le permite tener su propio estilo en el resto de la aplicación.
MetaFight
1
A veces, abstracciones como esa pueden ponerse un poco feas, haz todo lo posible para mantenerlo limpio, independientemente de las convenciones utilizadas, pero sobre todo, solo asegúrate de que la API que presentas de la abstracción sea de calidad suficiente para que no necesites volver en la intromisión en la abstracción y los consumidores podrán trabajar de manera consistente con sus abstracciones fácilmente para asegurarse de que su código no se convierta en un desastre como lo que puede haber en sus abstracciones. En resumen, no hay una buena respuesta, pero mientras tus abstracciones presenten buenas API, al menos evitarás que el problema se propague más allá de ellas.
Jimmy Hoffa
1
¿Qué quiere decir exactamente con "estilo de codificación" - cosas simples como el uso de "underscores / camelCase / PascalCase y ubicación de llaves, o cosas más complejas como el diseño de clase / método / función y el estilo imperativo / funcional?
Izkata

Respuestas:

10

Creo que depende de cuán grande sea el proyecto en general.

En un extremo, digamos que tiene un proyecto de 1 Mloc. Para un proyecto tan grande, es poco probable que un solo individuo sea un "experto" en todas las áreas involucradas. Entonces, en este caso, me quedaría con los estilos de código existentes para cada componente principal. Los nuevos desarrolladores elegirán un área, aprenderán eso y es poco probable que vean muchos otros componentes que pueden tener diferentes estilos de código.

Si el proyecto es mucho más pequeño, donde es probable que las personas comprendan toda la base del código, entonces elegiría un estilo de código dominante y seguiría con eso. En este caso, creo que la coherencia en todo el proyecto tiene más sentido porque es probable que los nuevos desarrolladores trabajen en todas las áreas del proyecto.

Los proyectos medianos son quizás los más difíciles de tomar esta decisión. En este caso, debe sopesar los costos de cada enfoque y decidir cuál cree que será menos costoso a largo plazo. El desafío es que los proyectos medianos generalmente han crecido lo suficiente como para que una refactorización de estilo completa parezca prohibitivamente costosa. Es posible que desee echar un segundo vistazo a la estructura de árbol de código para ver si se pueden organizar las cosas para agrupar estilos de código particulares.

De cualquier manera, la decisión final debe recaer en el equipo en el que estás que está armando este paquete.


Algunos de los valores atípicos que podrían cambiar mi razonamiento desde arriba:

  • Si uno o más de los módulos tienen un estilo atroz, entonces no tiene sentido mantener eso, incluso en un proyecto más grande. Sí, el estilo es subjetivo, pero si a ti y a tus compañeros participantes del proyecto realmente no les gusta la forma en que fluyen áreas particulares, destruye el viejo estilo y dale uno mejor.

  • Si todos los estilos están razonablemente cerca uno del otro, podría ser igual de fácil declarar "aquí está la nueva forma" y usarla para todos los códigos nuevos y refactorizaciones significativas. Esto puede hacer que las revisiones sean un poco molestas, pero en mi experiencia la mayoría de las personas son bastante capaces de adaptarse a este enfoque. También proporciona una señal indicadora de dónde está el código anterior.

  • A veces, el estilo cambia según la nueva funcionalidad agregada al lenguaje. C ++ ha recogido una serie de características a lo largo de los años. Puede tener sentido refactorizar, según sea necesario, el estilo más antiguo a un estilo más nuevo que aproveche esas características.

  • Algunas bibliotecas pueden tener un enfoque o estilo particularmente idiomático. Si es así, me quedaría con ese estilo para esa biblioteca, incluso si puede entrar en conflicto con el resto del proyecto. La intención aquí es aumentar las probabilidades de que alguien que trabaja frobnosticatorsen otros proyectos también trabaje en su proyecto.


Algunos de los comentarios mencionaron los estilos imperativos y orientados a objetos como una consideración.

Los módulos que son "pesados" en un estilo particular probablemente deberían permanecer así si el módulo es mediano o más grande. He trabajado con los tres estilos principales (imperativo, objetivo y funcional), y he refactorizado los estilos imperativos pesados ​​en un estilo OO. Con una cantidad de código media o mayor, la refactorización puede ser (excepcionalmente) difícil. Mi experiencia fue confusa porque no tenía ningún soporte de herramientas para ayudar en la refactorización.

Me imagino que existe una alta correlación entre los módulos de estilo imperativo y aquellos módulos que son idiomáticos para nichos de desarrollo particulares, lo que se remonta al último punto que planteé con valores atípicos. Por lo tanto, cualquier módulo que encuentre para esa funcionalidad se verá así, y desea que los expertos de ese dominio también puedan trabajar fácilmente en su proyecto. Pero si hay opciones y a su equipo no le gusta el estilo de ese módulo, entonces investigaría las opciones.

Del mismo modo, he trabajado con un módulo de estilo OO pesado donde los principios OO se llevaron demasiado lejos y se usaron incorrectamente. Como ejemplo, las interfaces se estaban utilizando como un sustituto de la herencia múltiple. Y como era de esperar, fue una implementación cruda. Pude hacer un progreso razonable en la refactorización de ese módulo, pero finalmente abandoné ese enfoque ya que encontré mejores paquetes para usar.


fuente
Esa es una buena manera de decirlo. Proyectos similares son alrededor de 300 KLOC.
Karl Bielefeldt
3

Parece que hay varias capas a considerar, al menos:

  1. Las bibliotecas existentes y sus modificaciones.
  2. Nuevo código de prueba unitaria para esas bibliotecas.
  3. La capa de abstracción.
  4. La API presentada por la capa de abstracción.
  5. Ejemplo y código de prueba usando la capa de abstracción.

Voy a suponer que no tiene sentido simplemente refactorizar todo el código a un estilo común por adelantado; si lo hubiera hecho, no habría hecho la pregunta.

Tomando en cada uno a su vez:

  1. Para la base de código existente, es probable que desee atenerse a ese estilo.
  2. El nuevo código de prueba unitaria para el código existente se encuentra en un área gris, particularmente dependiendo de cuánto esté integrado con el código anterior. Pero lo más probable es que intente hacerlo en el 'estilo preferido'.
  3. El nuevo código en la capa de abstracción. Al asegurarse de que esta es realmente una capa de código separada, no debería haber ninguna dificultad en usar un estilo preferido, incluso si el código está interactuando mucho con un estilo o estilos heredados. La mayoría del código necesita interactuar con otros estilos, y nunca he encontrado que esto sea un problema.
  4. Obviamente, la API en sí misma necesita la mayor atención y cumple con las máximas necesidades de usabilidad.
  5. Cualquier ejemplo o código de prueba también debería poder escribirse en el estilo preferido. Dependiendo de la integridad de la abstracción (es decir, si se oculta por completo las capas inferiores), esto puede ser fácil o difícil. Por supuesto, asegurarse de que el futuro código del cliente sea legible será uno de sus objetivos clave.

Algunas cosas que he encontrado personalmente es que con una gran base de código heredado:

  • Al establecer un estilo preferido y aplicar los cambios de código, no resulta mágicamente que todo el código antiguo migre al nuevo estilo.

  • A la mayoría de los ingenieros les gusta codificar (más o menos) el estilo existente en una biblioteca determinada. Exigir lo contrario resulta en mucha aplicación de la ley.

  • Requerir un estilo preferido en una biblioteca heredada tiende a dar lugar a una gran inconsistencia de estilo en esa biblioteca. Por lo tanto, para los estándares que se basan exclusivamente en la presentación, a diferencia de la solidez del código, también es difícil ver muchos beneficios al exigirlos.

Como tema final (un poco fuera del tema, pero creo que es relevante), la verdad es que algunos ingenieros luchan por atenerse a cualquier estándar de estilo que no sea el que mejor conocen. Recomiendo encarecidamente involucrar al equipo en las decisiones de estilo y asegurarse de que haya aceptación. Una vez hecho esto, está en una posición mucho mejor para aplicar realmente un estándar en código mixto.

Keith
fuente
0

Estaré de acuerdo con @MetaFight aquí en caso de que esté desarrollando un proyecto de gran tamaño con muchos módulos de terceros.

Vamos a mapear su problema con un problema verbal real: " Suponga que tiene un estilo de vida tranquilo en su casa. Le gusta que su lugar sea tranquilo, nunca habla más alto y nunca desea que ningún miembro de su familia lo haga. Pero interactúa con muchos diferentes personas afuera todos los días para traer algo para su casa. No necesariamente también hablarán en voz baja, en ese caso, usted se moldeará en consecuencia al tratar con esas personas. Por lo tanto, la interfaz o envoltura para estas personas es muy flexible por el simple hecho de su trabajo por hacer " . Ejemplo tonto ... jajaja

Pero mi punto es crear un contenedor para las bibliotecas según su estándar de codificación de tal manera que use estas bibliotecas a través de estos contenedores manteniendo su estilo de codificación original en el interior.

+1 para MetaFight.

theinsaneone
fuente
Exactamente la solución correcta de la OMI. Utilizo envoltorios para vincular el código que otras personas escriben para mis proyectos también. Defina una interfaz por adelantado y luego, cuando la implementen, puede envolverla y probarla en una caja negra.
Kieveli
1
¿Por qué se está rechazando esto? Claramente creo que es la mejor solución :)
MetaFight
0

Claramente causaría la menor cantidad de confusión usar un solo estilo de codificación a lo largo de su proyecto. El punto principal de usar un estilo de codificación en primer lugar es hacer que el código sea más fácil de leer y modificar.

En cuanto al estilo de código utilizado internamente en una biblioteca, no creo que sea relevante. Si la biblioteca es demasiado imperativa, entonces escribir un contenedor OO está bien, pero eso no requiere que use el mismo estilo de código que en los ejemplos o componentes internos de la biblioteca.

Gustav Bertram
fuente