Recientemente tuve una discusión con un colega sobre el estilo de código. Estaba argumentando que su uso de las API y los patrones generales que está utilizando debería ser lo más similar posible con el código circundante, si no con la base de código en su conjunto, tal como lo haría con la apariencia del código (posicionamiento de llaves, mayúsculas, etc.) . Por ejemplo, si estuviera agregando un método a una clase DAO en C #, trataría de usar LINQ cuando sea apropiado para ayudar a que mi código sea limpio y fácil de mantener, incluso si ninguno de los otros métodos en esa clase lo estuviera usando. Sin embargo, mi colega argumentaría que no debería usarlo en esa instancia porque estaría en contra del estilo existente de esa clase y, por lo tanto, es más difícil de entender.
Al principio encontré su posición bastante extrema, pero después de pensarlo un momento, estoy empezando a ver su punto. Con el ejemplo hipotético de LINQ, ¿tal vez esta clase no lo contiene porque mis colegas no están familiarizados con LINQ? Si es así, ¿no sería más fácil mantener mi código para mis compañeros desarrolladores si no lo usara? Por otro lado, si realmente creo que usar una técnica de este tipo daría como resultado un código más limpio, ¿no debería usarlo incluso si difiere drásticamente del código circundante?
Creo que el quid de la discusión de mi colega es que si todos implementamos una funcionalidad similar en una base de código de diferentes maneras, y cada uno cree que nuestro camino es "mejor", entonces al final el código en su conjunto se vuelve más difícil comprender. Sin embargo, en este momento sigo pensando que si seguimos ciegamente el código existente demasiado, la calidad se pudrirá lentamente con el tiempo.
Entonces, ¿en qué medida los patrones son parte del estilo de código, y dónde debemos trazar la línea entre mantenerse consistente y hacer mejoras?
fuente
IEnumerable
s en lugar de un DAO.Respuestas:
Para dar una respuesta más general:
En un caso como este, tiene dos "mejores prácticas" de programación que son opuestas entre sí: la consistencia del código es importante, pero también lo es elegir el mejor método posible para cumplir su tarea. No hay una respuesta correcta a este dilema; depende de un par de factores:
¿Qué tan beneficiosa es la forma "correcta"?
¿Qué gran problema crearía la inconsistencia?
Con base en el balance de estos problemas, debe tomar la decisión correcta sobre qué ruta tomar. Personalmente veo poco valor en la coherencia por el bien de la coherencia, y preferiría usar los mejores y más recientes métodos a menos que haya un costo significativo para hacerlo.
Por supuesto, hay una tercera opción: reescribir el código existente para que use los mejores métodos y sea coherente. Hay momentos en que esto es necesario, pero tiene un alto costo.
fuente
Mantenerse constante tiene poco valor en mi perspectiva; Hacer mejoras continuamente es una necesidad.
La posición de su colega realmente impide la innovación. El argumento de coherencia lo lleva a una situación en la que puede usar, por ejemplo, LINQ solo si migra todo el código para usar LINQ. Y bueno, no tenemos tiempo para esto, ¿verdad?
Prefiero tener una inconsistencia en la que todavía se está haciendo algún código
foreach
sobre ArrayLists y otras partes usan LINQIEnumerable<T>
, en lugar de apegarse a la forma más antigua de hacer las cosas hasta el final de los tiempos.Es responsabilidad de sus colegas mantenerse relevantes y aprender nuevas formas de hacer las cosas.
fuente
La coherencia de la API es muy importante, tanto para las API públicas como para las internas.
La coherencia del formato del código es importante, y lo ideal es que se aplique mediante una herramienta de formato automático con las mismas reglas de formato para todos. Hace que vivir con una base de código compartida controlada por versiones sea más fácil.
Las convenciones de nomenclatura deben ser consistentes, también para cosas como variables locales, etc.
Las herramientas de análisis estático deben usarse para hacer cumplir ciertas otras convenciones y buenas prácticas (pero no sigas ciegamente los valores predeterminados de dicha herramienta, los valores predeterminados a veces pueden limitarse a locos), aunque si algo lo exige, no tengas miedo de desactivar algunos marque (generalmente con una directiva dentro de un comentario) temporalmente, si puede justificarlo.
Lo que sucede dentro de las funciones / métodos , aparte de lo que se menciona anteriormente, no necesita ser coherente de ninguna manera, siempre que sea un buen código por sí solo . Un código bueno, comprensible y bien comentado es muy importante, pero después de eso, si el compilador y las herramientas de análisis estático piensan que es un código consistente, es lo suficientemente consistente.
Acerca de las nuevas características del lenguaje como LINQ (bueno, eso no es exactamente nuevo), lo único que debe considerarse es, ¿se utilizará una versión lo suficientemente nueva del idioma / bibliotecas en todas partes donde se utilizará el código? En caso de duda, quédese con las características que se sabe que son compatibles. Por supuesto, esto no le impide impulsar una actualización de versión en todo el sistema, por lo que puede comenzar a usar las nuevas cosas buenas.
Y cada desarrollador que trabaje con código debe mantenerse actualizado, por lo que cualquier desarrollador de .NET debe conocer LINQ, y si no lo hacen, deben verse obligados a aprender, por su propio bien (nunca se sabe cuándo buscará un nuevo trabajo en este negocio, por una razón u otra).
fuente
La respuesta a esto es simple.
La consistencia es de suma importancia.
pero viene con una advertencia ...
Es probable que usted y su compañero de trabajo estén obsesionados con el tipo incorrecto de consistencia.
Las implementaciones son desechables. Se pueden revisar por completo con distintos grados de facilidad según la calidad y la amplitud del conjunto de pruebas. Preocuparse por cosas como "¿Debería ser esto una propiedad?", "¿No deberían los códigos delgados usar LINQ en lugar de una construcción de nivel inferior?" Es de dudoso valor. Es difícil vincular cualquier medida al valor de consistencia en el nivel de implementación. Una pregunta mucho mejor para hacer a este nivel es "¿Este código funciona como se anuncia?". La coherencia de la implementación de TL; DR es donde las "mentes pequeñas" obtienen su duende.
¿Por qué la consistencia no es tan importante aquí? Las implementaciones generalmente tienen una pequeña cantidad de contribuyentes. La mayoría de los métodos están escritos y nunca se vuelven a tocar. Del código restante, el número de métodos que tienen dos contribuyentes es casi seguro una mayoría. Este patrón continúa hasta el infinito . En este contexto, la consistencia no es tan importante. Si la vida útil del código es bastante pequeña ( unos pocos años ), las ganancias de la consistencia agresiva probablemente no sean un factor.
Esto no quiere decir que deba volverse loco en sus implementaciones. Más bien es decir que un diseño agradable, limpio y simple será de gran valor para su hipotético futuro mantenedor que la tonta consistencia de la placa de caldera método por método. Esto nos lleva al punto real ...
Las API no son desechables.
Este es todo el nivel de código de API, servicios web, SDK, etc. Estos deben, deben, DEBEN ser consistentes. Las ganancias de productividad de esta variedad de consistencia son enormes por varias razones:
Pruebas de integración:
Si mantiene la coherencia de su API, puede crear conjuntos de pruebas de integración. Esto permite a los desarrolladores intercambiar libremente los detalles de implementación y lograr la validación inmediata. ¿Quieres cambiar tu basura de trabajo a LINQ? ¿Se ejecutan las pruebas de integración? También proporciona validación cuando se prepara para ir a producción. Debido a que las computadoras son rápidas, una sola computadora portátil puede realizar el trabajo de miles de evaluadores que ejecutan tareas mundanas. Es equivalente a aumentar considerablemente el personal de su organización.
Productividad
Cuando las API son consistentes, puede adivinar cómo usar una API simplemente siguiendo lo que aprendió sobre el uso de otras partes de la API. Esto se debe a que la API ofrece una apariencia y sensación natural y consistente. Significa que su cliente pasa menos tiempo revisando la documentación. La incorporación es más fácil y más barata. Se hacen menos preguntas a las personas que desarrollaron la API. La consistencia hace que todos sean ganadores
¿Por qué es importante la coherencia en este escenario? Porque las API tienen exactamente el problema opuesto de las implementaciones. El número de personas que los usan es generalmente mucho mayor que el número de personas que contribuyen a sus implementaciones. Las pequeñas ganancias de un poco de consistencia se multiplican y los costos de mantener esa consistencia se amortizan.
Conclusión
La consistencia es cara. A primera vista, reduce la productividad. Restringe a los desarrolladores y les dificulta la vida. Establece limitaciones en las formas en que pueden resolver un problema, a veces obligándolos a resolverlo de una manera no óptima. Esto es a menudo por razones que no entienden, están mal concebidas o no están al tanto (contratos, políticas organizacionales o interorganizacionales más amplias).
Raymond Hettinger hizo algunos puntos excelentes en su charla de Pycon 2015 sobre el uso de la guía de estilo PEP8 para equipos de programadores de Python. Mostró que la obsesión por la coherencia estilística en un fragmento de código provocó que los revisores de código omitieran serias fallas lógicas y de diseño. Su hipótesis se puede resumir en que encontrar inconsistencias estilísticas es fácil; determinar la calidad real de un código es difícil
El punto aquí es ser crítico. Identifique dónde es importante la consistencia y protéjala agresivamente. Donde no es importante no pierdas tu tiempo. Si no puede proporcionar una forma objetiva de medir el valor de la consistencia (en los casos anteriores "personal efectivo", costo en función de la productividad) y no puede demostrar que los rendimientos son sustanciales, entonces probablemente esté haciendo un mal servicio a tu organización.
fuente
El lenguaje C # todavía está evolucionando. Si las personas no aprendieran los cambios de C # 1, se estarían perdiendo:
Esta es solo una pequeña selección de características comunes que se encuentran en el artículo de Wikipedia. Lo que quiero decir es que si los desarrolladores no aprenden, la base de código permanecerá en el vacío. Uno esperaría que sus desarrolladores mejoren continuamente y la base del código evolucione, respaldada por un conjunto de pruebas completo. ¿Recuerdas lo malo que fue con .NET 1 para implementar propiedades manualmente?
Linq hace la vida más fácil. Úselo donde pueda. Puede motivar a los miembros de su equipo.
Las mejoras son graduales. Para mí, no tiene sentido mantener un código de estilo antiguo que sea menos legible y potencialmente menos mantenible. Los miembros de su equipo al menos deberían poder resolver lo que está sucediendo, incluso si no pueden escribirlo.
fuente
Debe ser coherente, pero no necesariamente con el código anterior. Es decir, su equipo debe acordar la forma correcta de hacer algo, y usarlo de esa manera cada vez que se escriba un nuevo código o se realicen cambios sustanciales.
De esa manera, cosechará la mayoría de los beneficios de la coherencia (en particular, no importará quién escriba el código), pero aún puede mejorar si el equipo ve un beneficio claro al hacer las cosas de otra manera.
En un mundo ideal, reescribiríamos todo el código antiguo para adaptarlo a la nueva forma correcta. Si bien esto no es económicamente viable, debería tener sentido técnico (o de lo contrario, la nueva forma no es una mejor manera), y su plan a largo plazo debería ser actualizarlo. Si eso no vale la pena, no te molestes con la nueva forma. Dicho de otra manera, debe haber una clara ventaja en la nueva forma de considerar declararla correcta.
fuente
Creo que es importante seguir un estilo de código en un proyecto, por ejemplo. convenciones de nomenclatura, muescas, etc.
No estoy de acuerdo con que deba limitarse a usar nuevas construcciones de lenguaje o patrones de diseño simplemente porque sus colegas no los entienden o no se han utilizado en el proyecto antes.
Por supuesto, estas cosas deberían tener buenas razones para usarlas, por ejemplo. rendimiento o brevedad, si corresponde.
fuente
Sería extremadamente cuidadoso siguiendo ciegamente los patrones de diseño actuales. Por supuesto, cuando no hay una desventaja apreciable, siempre se debe intentar seguir patrones similares en la base del código.
Sin embargo, es demasiado fácil entrar en circunstancias en las que la mayoría de los desarrolladores sienten que es una "mejor práctica" seguir los malos patrones existentes que conducen a situaciones en las que los buenos desarrolladores escriben código malo e imposible de mantener.
Por otro lado, la consistencia es importante. Cuando se trata de enormes bases de código, es extremadamente útil tratar de seguir patrones similares para que, aunque los desarrolladores no hayan leído cada centímetro de la base de código, sepan qué esperar.
Por lo tanto, creo que es mejor establecer y actualizar pautas sobre qué patrones deben seguir los desarrolladores si es posible. De esta manera, cualquier código nuevo es consistente con otro código nuevo.
fuente
Tenemos reuniones técnicas regulares, bastante informales, que cualquiera de nosotros puede realizar. Si encontramos una nueva técnica, la presentamos en la reunión. En general, tiene una buena idea de lo bien que sus colegas aceptan y entienden la idea. Esto le ayuda a decidir si es conveniente incluirlo en su código, ayuda a otros a descifrarlo si lo hace y también establece la persona 'ir a' si otros necesitan ayuda con ese estilo. Si nadie reinventara la rueda, todavía estaríamos arrastrando cosas en los registros.
fuente