Vergonzosamente, introduje una biblioteca "común", nombrada como tal, en un entorno de equipo hace un par de décadas. Realmente no entendía la dinámica de lo que podría suceder en un entorno de equipo poco coordinado en cuestión de meses.
Cuando lo presenté, pensé que lo había dejado claro y también documenté que es para cosas que todos estaríamos de acuerdo en que encontramos útiles a diario, que pretende ser una biblioteca minimalista y que la biblioteca no debe depender de nada más que biblioteca estándar para que sea tan fácil de implementar como sea posible en nuevos proyectos. En ese momento, pensaba que era nuestra pequeña extensión de la biblioteca estándar para cosas que, en nuestro dominio particular, encontramos útiles a diario.
Y comenzó lo suficientemente bien. Comenzamos con una biblioteca matemática (common/math*
) de rutinas que todos usábamos a diario, ya que estábamos trabajando en gráficos de computadora que a menudo eran pesados en el álgebra lineal. Y como a menudo interaccionábamos con el código C, acordamos algunas funciones útiles de utilidad como las find_index
cuales, a diferencia destd::find
en C ++, devolvería un índice a un elemento encontrado en una secuencia en lugar de un iterador que imitaba cómo funcionaban nuestras funciones en C, cosas de este tipo, un poco eclécticas pero minimalistas y lo suficientemente utilizadas como para ser familiares y prácticas para todos , y la familiaridad instantánea es un criterio extremadamente importante, ya que lo veo al tratar de hacer cualquier cosa que sea "común" o "estándar", ya que si realmente es "común", debería tener esa calidad familiar como resultado de su amplia adopción y uso diario.
Pero con el tiempo, las intenciones de diseño de la biblioteca se escaparon de mis dedos cuando la gente comenzó a agregar cosas que usaban personalmente que simplemente pensaron que podrían ser útiles para otra persona, solo para encontrar a nadie más usándola. Y más tarde, alguien comenzó a agregar funciones que dependían de OpenGL para rutinas comunes relacionadas con GL. Más adelante, adoptamos Qt y la gente comenzó a agregar código que dependía de Qt, por lo que la biblioteca común ya dependía de dos bibliotecas externas. En algún momento, alguien agregó rutinas de sombreadores comunes que dependían de nuestra biblioteca de sombreadores específicos de la aplicación, y en ese punto ni siquiera podía implementarlo en un nuevo proyecto sin incorporar Qt, OGL y nuestra biblioteca de sombreadores específicos de la aplicación y escribir un script de compilación no trivial para su proyecto. Entonces se convirtió en este lío ecléctico e interdependiente.
Pero también descubrí al debatir qué debería o no entrar en esta biblioteca que lo que se considera "común" puede convertirse fácilmente en una idea muy subjetiva si no establece una regla de línea muy estricta de que lo que es "común" es lo que todos tienden a encontrar útil a diario. Cualquier aflojamiento de los estándares y se degrada rápidamente de cosas que todos encuentran útiles diariamente a algo que un desarrollador único encuentra útil que podría tener la posibilidad de ser beneficioso para otra persona, y en ese momento la biblioteca se degrada en un lío ecléctico muy rápido .
Pero, además, cuando llegue a ese punto, algunos desarrolladores pueden comenzar a agregar cosas por la simple razón de que no les gusta el lenguaje de programación. Es posible que no les guste la sintaxis de un bucle for o una llamada de función, momento en el que la biblioteca comienza a llenarse de cosas que solo combaten la sintaxis fundamental del lenguaje, reemplazando un par de líneas de código directo que no es realmente duplicar cualquier lógica en una sola línea concisa de código exótico que solo es familiar para el desarrollador que introdujo tal taquigrafía. Entonces, tal desarrollador podría comenzar a agregar más funcionalidades a la biblioteca común implementada usando tales shorthands, en ese punto, secciones importantes de la biblioteca común se entrelazan con estas exóticas shorthands que pueden parecer hermosas e intuitivas para el desarrollador que la introdujo, pero feas, extrañas y difíciles de entender para todos los demás. Y en ese punto creo que sabes que cualquier esperanza de hacer algo verdaderamente "común" se pierde, ya que "común" y "desconocido" son ideas polares opuestas.
Así que hay todo tipo de latas de gusanos allí, al menos en un entorno de equipo poco coordinado, con una biblioteca con ambiciones tan amplias y tan generalizadas como simplemente "cosas de uso común". Y aunque el problema subyacente podría haber sido la falta de coordinación por encima de todo lo demás, al menos varias bibliotecas destinadas a servir a un propósito más singular, como una biblioteca destinada a proporcionar rutinas matemáticas y nada más, probablemente no se degradarían tan significativamente en términos de su Diseñe la pureza y las dependencias como una biblioteca "común". Entonces, en retrospectiva, creo que sería mucho mejor errar del lado de las bibliotecas que tienen intenciones de diseño mucho más claras. También he descubierto a lo largo de los años que el propósito limitado y la aplicabilidad limitada son ideas radicalmente diferentes.
Además, al menos soy un poco poco práctico y me importa demasiado la estética, pero la forma en que tiendo a percibir mi idea de la calidad de una biblioteca (y tal vez incluso la "belleza") se juzga más por su eslabón más débil que es más fuerte, de manera similar que si me presentas la comida más atractiva del mundo pero, en el mismo plato, pones algo podrido allí que huele realmente mal, tiendo a querer rechazar todo el plato. Y si eres como yo en ese sentido y haces algo que invita a todo tipo de adiciones como algo llamado "común", es posible que te encuentres mirando esa placa analógica con algo podrido a un lado. Del mismo modo, creo que es bueno si una biblioteca está organizada, nombrada y documentada de tal manera que no Invite a más y más y más adiciones con el tiempo. Y eso incluso puede aplicarse a sus creaciones personales, ya que ciertamente he creado algunas cosas podridas aquí y allá, y "contamina" mucho menos si no se agrega al plato más grande. Separar las cosas en bibliotecas pequeñas y muy singulares también tiende a desacoplar mejor el código, aunque solo sea por la simple virtud de que resulta mucho menos conveniente comenzar a acoplar todo.
La desduplicación del código se ha introducido en mí a lo largo de los años, pero siento que debería intentarlo esta vez.
Lo que podría sugerir en su caso es comenzar a tomarlo con calma en la deduplicación de código. No estoy diciendo que copie y pegue fragmentos grandes de códigos propensos a errores mal probados ni nada por el estilo, ni duplicar grandes cantidades de código no trivial que tiene una probabilidad decente de requerir cambios en el futuro.
Pero especialmente si tiene la mentalidad de crear una biblioteca "común", para lo cual asumo que su deseo es crear algo ampliamente aplicable, altamente reutilizable y quizás idealmente algo que encuentre tan útil hoy como lo hace dentro de una década. , a veces incluso puede que necesite o desee duplicación para lograr esta escurridiza calidad. Porque la duplicación en realidad podría servir como un mecanismo de desacoplamiento. Es como si quisieras separar un reproductor de video de un reproductor de MP3, entonces al menos tienes que duplicar algunas cosas como baterías y discos duros. No pueden compartir estas cosas o de lo contrario están acoplados de manera indivisible y no se pueden usar independientemente el uno del otro, y en ese momento las personas podrían no estar interesadas en el dispositivo si todo lo que quieren hacer es reproducir MP3. Pero algún tiempo después de separar estos dos dispositivos, es posible que el reproductor de MP3 pueda beneficiarse de un diseño de batería diferente o un disco duro más pequeño que el reproductor de video, en ese momento ya no está duplicando nada; lo que inicialmente comenzó como una duplicación para permitir que este dispositivo interdependiente se dividiera en dos dispositivos separados e independientes podría resultar en diseños e implementaciones que ya no son redundantes.
Vale la pena considerar las cosas desde la perspectiva del que usa una biblioteca. ¿De verdad quieres usar¿Una biblioteca que minimiza la duplicación de código? Lo más probable es que no lo haga porque uno que sí dependerá naturalmente de otras bibliotecas. Y esas otras bibliotecas pueden depender de otras bibliotecas para evitar duplicar su código, y así sucesivamente, hasta que necesite importar / vincular 50 bibliotecas diferentes para obtener algunas funciones básicas como cargar y reproducir un archivo de audio, y eso se vuelve muy difícil de manejar . Mientras tanto, si una biblioteca de audio de este tipo eligió deliberadamente duplicar algunas cosas aquí y allá para lograr su independencia, se volverá mucho más fácil de usar en nuevos proyectos, y es probable que no necesite actualizarse tan a menudo desde que ganó ' No es necesario cambiar como resultado de una modificación de sus bibliotecas externas dependientes que podrían estar tratando de cumplir un propósito mucho más generalizado que el que necesita la biblioteca de audio.
Entonces, a veces vale la pena elegir deliberadamente duplicar un poco (conscientemente, nunca por pereza, en realidad por diligencia) para desacoplar una biblioteca y hacerla independiente porque, a través de esa independencia, logra una gama más amplia de aplicabilidad práctica y incluso estabilidad (no más acoplamientos aferentes). Si desea diseñar las bibliotecas más reutilizables posibles que le duren de un proyecto al siguiente y a lo largo de los años, además de reducir su alcance al mínimo, sugeriría considerar duplicar un poco aquí. Y, naturalmente, escriba pruebas unitarias y asegúrese de que esté realmente probado y confiable en lo que está haciendo. Esto es solo para las bibliotecas que realmente desea tomarse el tiempo para generalizar a un punto que va mucho más allá de un solo proyecto.