Por qué son importantes las estructuras de carpetas

JOSE MENDEZ / UNITY TECHNOLOGIESSenior Software Developer
Dec 28, 2023|16 minutos
Por qué son importantes las estructuras de carpetas
Para tu comodidad, tradujimos esta página mediante traducción automática. No podemos garantizar la precisión ni la confiabilidad del contenido traducido. Si tienes alguna duda sobre la precisión del contenido traducido, consulta la versión oficial en inglés de la página web.

Como consultor del equipo de Éxito del Cliente , a menudo me preguntan: “¿Hemos construido correctamente nuestros paquetes de activos?” o una variación de esta pregunta. Mi respuesta siempre es la misma: Depende del proyecto. Luego hablo con los clientes sobre los detalles. Aunque esta respuesta es correcta, no proporciona ninguna información que pueda ayudar a proyectos futuros.

Si bien es un dilema común, me cuesta encontrar una respuesta más general a la pregunta (a pesar de nuestras pautas y mejores prácticas existentes para los destinatarios). Algunos usuarios no saben si los paquetes son correctos para comenzar y mi tiempo a menudo se limita a examinar proyectos para optimizar la memoria. Esto significa que no puedo determinar el uso previsto de cada activo en un proyecto. Además, a medida que un proyecto escala, puede resultar imposible para una sola persona responder la misma pregunta para todos y cada uno de los activos.

Al final, me di cuenta de algo: La cuestión de construir paquetes de activos limita correctamente la perspectiva para encontrar una respuesta más general. Déjame explicarte.

Un paquete de activos ocupa memoria para cargarse, por lo que si los activos están agrupados junto con otros activos que no se cargan y descargan al mismo tiempo, no está utilizando la memoria de manera tan óptima como podría. Por lo tanto, preguntar si un activo está en el paquete correcto o si los paquetes tienen los activos correctos en ellos es esencialmente la pregunta de si está cargando los activos correctos en el momento correcto. La respuesta a cuándo se deben cargar activos específicos es cuál es el uso previsto de ese activo, por lo que la respuesta suele ser: "Depende del proyecto". En la práctica, he descubierto que aprender el uso previsto del activo revela cómo se cargan los activos en la memoria y cómo deben agruparse.

Así pues, la frase clave es “uso previsto”: ¿Quién sabe cuál es el uso previsto de un activo? ¿Cómo comunicar esa intención a todo el mundo? Y finalmente ¿cuándo debería ocurrir esto?

En mi opinión, hay un momento en el que la respuesta a esta pregunta es clarísima: en la creación y modificación de activos. Ya sea una textura específica para un personaje, un sombreador de iluminación global o una malla de árbol para usar en múltiples niveles de juego, el creador conoce su uso previsto y, por lo tanto, es el más indicado para comunicar esa intención. Los artistas pueden comunicar esta intención implementando una convención de nombres de archivos consistente y agrupando los archivos con los mismos usos previstos en la misma carpeta.

Los programadores y otros miembros del equipo pueden luego usar esta información para decidir cuándo y si un activo debe agruparse con otros activos que se cargarán simultáneamente. Por este motivo, el uso previsto de un activo debe quedar muy claro (de un vistazo) durante todo el proyecto, y el directorio de archivos actúa como fuente de información para todos los miembros del equipo.

En esta publicación de blog, analizaré algunas prácticas recomendadas y casos extremos comunes que espero le ayuden a estructurar mejor proyectos futuros. Primero, analicemos algunas de las estructuras de carpetas más comunes y sus problemas.

Estructuras de carpetas

Según mi experiencia, hay cuatro tipos de estructuras de carpetas: aleatoria, por tipo de activo, por característica y por propósito. De estos, el último es el mejor con diferencia, porque transmite la intención y, por tanto, es el más adecuado para una estrategia de agrupación óptima.

Aleatorio no es algo que veo a menudo. Esto sucede principalmente con desarrolladores individuales que pueden no estar familiarizados con el desarrollo de software, y esto se vuelve insostenible, por razones obvias, a medida que el proyecto crece en tamaño o complejidad. La falta de estructura, o una estructura aleatoria, conlleva muchos problemas: los activos son difíciles de encontrar y comprender el uso previsto es prácticamente imposible.

La estructuración por tipo de activo es bastante común, ya que así es como muchos artistas trabajan en los activos antes de importarlos al motor. Si conoce el tipo de activo, encontrar su ubicación es fácil, pero todo lo demás queda oculto. Incluso con una excelente convención de nombres, puede ser difícil determinar si un personaje, entorno, interfaz de usuario o cualquier combinación de los tres requiere un sombreador, una textura, una malla, etc. específicos. Un directorio de archivos apropiado no debe ocultar la información, sino revelarla.

Las estructuras de carpetas por característica son poco frecuentes, pero parecen sensatas a primera vista. Muchas empresas se dividen en equipos de funciones, entonces ¿por qué no agrupar los datos de manera similar? Bueno, no es así como el juego utiliza los datos. En el pasado, he visto ejemplos, como sombreadores y audio, que deberían agruparse, pero como están creados por equipos diferentes, esta verdad se oscurece.

Un directorio de archivos con una convención de nombres clara impulsada por el propósito de los activos evita estos problemas. Para ilustrarlo, utilizaré un ejemplo de juego ficticio llamado “Dinosaur Brawl”.

Pelea de dinosaurios

Para los propósitos de este ejemplo, Dinosaur Brawl es un juego de acción y aventuras en tercera persona en 3D donde el jugador elige un dinosaurio para controlar en un vasto mundo abierto con múltiples biomas, luchando contra otros dinosaurios y criaturas prehistóricas en un intento de hacerse más fuerte y pasar sus genes a la siguiente generación, todo en una lucha gigante para sobrevivir a la próxima Edad de Hielo. El juego está diseñado para dispositivos móviles y algunos de los datos se distribuirán como parte de la aplicación original. El resto se descargará desde una CDN según sea necesario.

Podemos diseñar una estructura de carpetas general para todo el proyecto a partir de la sinopsis anterior. Dado que el jugador puede seleccionar y luchar contra otros dinosaurios, tiene sentido crear una carpeta por dinosaurio que contendrá todos los recursos específicos de ese dinosaurio: mallas, efectos de sonido, texturas, animaciones, efectos de partículas, etc. Los clasificaré como activos únicos.

Como es un juego de acción, tendrá entornos que son biomas separados. Por lo tanto, deberíamos crear una única carpeta para cada bioma o nivel del proyecto: llanuras, desiertos, tundra, pantanos, volcanes, etc.

Por supuesto, también habrá activos cuya presencia será necesaria para secciones enteras del juego. Uno de estos conjuntos son los elementos de la interfaz de usuario. Puedes pensar en estos activos como activos globales. Al igual que creamos una carpeta para todos los activos únicos, debería haber una carpeta global que se encuentre en la parte superior de la jerarquía de carpetas. Por ejemplo, una carpeta de IU global, una carpeta de Dinosaurio global, una carpeta de Entorno global, etc. De esta manera, todo lo que comparten estas secciones del juego se almacena en un solo lugar.

Activos compartidos

Esta categoría de activos se define como compartida por algunos Activos Únicos pero no por todos. Como tales, no encajan en las categorías de activos globales o únicos. Para Dinosaur Brawl, un ejemplo de este tipo de activos compartidos podrían ser aquellos que están presentes en todos los dinosaurios voladores, como partículas, shaders y efectos de sonido necesarios para dar la sensación de volar por el aire.

Lo que suele ocurrir es que estos activos se guardan en la carpeta del primer dinosaurio que los necesita. Lamentablemente, esto no describe con precisión cómo deben usarse y, por lo tanto, confunde su intención. En el peor de los casos, los activos se duplican en cada paquete de dinosaurio volador, lo que resulta ineficiente para la memoria, la depuración y el tamaño de la aplicación.

La mejor solución es crear una nueva carpeta con un nombre que indique su uso previsto, como Dinosaurios Voladores. Los detalles para decidir la ubicación son más complicados; no existe un estándar. Prefiero colocarlos en una subcarpeta al mismo nivel que las carpetas de dinosaurios globales y únicas, pero colocarlos con otras carpetas únicas es igualmente adecuado.

Cambios intencionales

Un caso extremo típico con esta convención es cuando los requisitos del proyecto cambian y un activo que originalmente estaba destinado a ser único se vuelve compartido. En nuestro ejemplo de Dinosaur Brawl , para ahorrar tiempo de desarrollo, se toma la decisión de utilizar el prefabricado Velociraptor como base para todos los demás Raptors (como el Utahraaptor, el Dokataraptor, etc.).

Sin embargo, lo que los desarrolladores no se dan cuenta es que cuando se agrega el prefabricado Velociraptor a un paquete, todos los recursos de Velociraptor se descargarán cuando se carguen todos los demás raptores, lo que aumenta los tiempos de descarga a pesar de que solo se usa el prefabricado.

Esto sucedió porque se cambió la intención del activo y la estructura de la carpeta ya no lo refleja. Cuando ocurre un cambio de intención, la ubicación y el nombre de los activos deben actualizarse para reflejarlo, a fin de mantener la coherencia y la precisión en el sistema. Esto comunica al equipo que crea los paquetes qué activos deben estar en un paquete “Shared Raptor” y cuáles deben permanecer en el modelo Unique Velociraptor.

Uso no previsto

Uno de los casos extremos más comunes y difíciles de solucionar es cuando un activo se utiliza de manera no intencional, de una forma para la que nunca fue previsto. Cuando esto sucede, normalmente se trata de un accidente. Por ejemplo, alguien tiene una fecha límite que cumplir y utiliza un activo ya existente en el proyecto para terminar el trabajo rápidamente.

Tomemos este escenario: Un artista está agregando un tutorial para una próxima expansión de Dinosaur Brawl y encuentra un sombreador de “brillo dorado” para acentuar cuándo los jugadores pueden hacer un contraataque a los enemigos de élite. Lo que el artista no sabe es que este shader es contenido del final del juego contra un T-Rex gigante: es un jefe único que tiene muchos recursos agrupados. Ahora todos estos activos se descargarán durante el tutorial, en un lugar donde la mayoría de los activos no se utilizan. Este paquete es enorme, por lo que el sistema que normalmente descarga recursos menores como este en medio de un juego se ve estresado, lo que provoca desde picos de rendimiento hasta fallas porque los jugadores con conexiones deficientes no pueden descargar el recurso lo suficientemente rápido.

El ejemplo anterior es extremo, pero totalmente realista, y lo he visto suceder en más de un proyecto. Es por esto que, además de la estructura de carpetas, todos los activos deben tener un nombre que comunique su intención. Si el sombreador se llamara gold_glow_trex_endgame, por ejemplo, sería evidente cuál era su uso previsto. Luego, durante la depuración, será obvio que este activo no debe cargarse durante el tutorial.

Soluciones de programación

Si está familiarizado con Addressables, es posible que sepa que los grupos y las etiquetas se utilizan para agrupar y etiquetar activos de la misma manera que sugerí en el ejemplo del juego anterior: mediante el uso de carpetas y convenciones de nombres sensatas. Quizás te preguntes: “¿Por qué molestarse con todo esto si puedes hacerlo usando grupos y etiquetas?”

Mi respuesta es que deberías hacer ambas cosas. Como expliqué al principio, a medida que aumenta el número de activos en un proyecto, se hace más difícil y eventualmente imposible para una persona saber cómo deben usarse todos los activos. Saber que los grupos de Addressables deben coincidir con la estructura de carpetas puede servir como una forma de confirmar que están configurados correctamente.

He visto a muchos de nuestros clientes que utilizan paquetes de activos sin códigos Addressables codificados en sistemas complejos como solución a este problema. Por ejemplo, crearán y mantendrán una lista maestra que se utiliza para crear los paquetes, o verificarán las confirmaciones de control de versiones para comparar los cambios en los paquetes, etc. Mi experiencia me ha demostrado que estas soluciones no son rentables a largo plazo. Es otro sistema más a desarrollar y mantener, lo que crea puntos de fallo adicionales. A medida que el proyecto crece, se ve afectado por una gran cantidad de excepciones y casos extremos que los proyectos de larga duración acumulan naturalmente. Lo peor de todo es que, a un nivel fundamental, fracasan porque no tienen remedio para los errores del usuario.

Conclusión

Un sistema de carpetas bien estructurado y una convención de nombres de archivos deberían dar como resultado una coincidencia 1 a 1 para paquetes de activos y grupos de archivos direccionables. La categorización de los archivos en grupos lógicos y subcarpetas garantiza que todos los miembros del equipo interpreten y localicen los archivos de manera uniforme, lo que mitiga posibles malentendidos y discrepancias a medida que el personal cambia y los requisitos del proyecto evolucionan. Los creadores de activos pueden facilitar el acceso y la navegación, ahorrándoles a otros miembros del equipo la tarea que requiere mucho tiempo de buscar activos específicos. Un enfoque sistémico ahorra tiempo valioso y minimiza la probabilidad de errores y descuidos. Convertirse en un referente duradero, una fuente de verdad, facilitando el proceso de incorporación de nuevos miembros al equipo y garantizando la viabilidad del proyecto a lo largo del tiempo.

¿Buscas ayuda o asesoramiento sobre la estructura de carpetas? Chatea con nosotros en los foros. Y consulte más blogs técnicos de los desarrolladores de Unity como parte del trabajo en curso. Serie Tecnología de las Trincheras.