En esta entrada vamos a ver que son los Assembly Definitions y cómo se utilizan en Unity, veremos cómo crearlos y configurarlos, por qué son tan importantes y qué beneficios nos aportan.
Si habéis programado en Java o Python, podríamos ver los Assemblies como packages o módulos de estos lenguajes. Al final los Assembly nos ayudan a separar nuestros namespaces
con todos los beneficios que esto nos aporta.
Cómo crear Assembly Definitions en Unity
Supongamos que tenemos el siguiente código:
public class EntityA
{
public void Something()
{
}
}
public class UseCaseA
{
public void DoSomething()
{
new EntityA().Something();
}
}
Simplemente la clase UseCaseA está consumiendo a la clase EntityA. Ahora queremos crear un Assembly para que todo el namespace de UseCase se pueda comunicar con el de Entity pero el de Entity no pueda hablar con el de UseCase.
Esto es muy sencillo, solo tenemos que ir a la carpeta donde queremos crear el Assembly, pulsar con el botón derecho y darle a crear Assembly Definition.
Hacemos lo mismo para la carpeta Entity y ahora lo que tendremos que hacer es crear la relación.
Con esto ya tendríamos nuestros Assemblies creados y relacionados de forma que forzamos a seguir la estructura que queremos.
Dentro de la configuración del Assembly también podemos indicarle para que plataforma queremos que se compile. Podemos hacer que una carpeta solo se compile en Android y otra en iOS, esto es lo que suelen hacer los plugins.
También podemos especificar que una carpeta se compile solo en Editor, lo cual quiere decir que este código solo estará disponible en el editor. Esta configuración la utilizaremos cuando hagamos Tests o tengamos algún código que nos queramos asegurar de que nunca está en una Build de producción como los cheats.
¿Pero qué ventajas tiene esto?
Beneficios
Assembly Definitions para reducir los tiempos de compilación
El primer beneficio es que mejoran los tiempos de compilación. Utilizar Assemblies hace que el ciclo de desarrollo sea más ágil.
Esto se debe a que cada Assembly se compila por separado, si tenemos dos Assemblies en el proyecto y modificamos el contenido de uno, Unity solo va a recompilar esa parte del proyecto en lugar de recompilarlo todo.
En el caso del ejemplo que hemos visto antes si modifico la clase EntityA solo se compilaría ese Assembly. Obviamente si lo que hago es cambiar el nombre de alguna función publica también afectará a los consumidores de otros Assemblies.
Esto en proyectos pequeños tal vez no tenga mucha importancia, pero a medida que crece el proyecto empieza a ganar relevancia.
Ya sabéis que cuanto más corto es el tiempo de iteración más veces podemos iterar, por lo que podemos fallar antes y por lo tanto corregirlo antes. Además más felices serán los desarrolladores en nuestro proyecto, y esto siempre se agradece.
Los Assemblies nos ayudan a organizar el proyecto
Nos ayudan a organizar el proyecto, con cada Assembly que creamos es como si estuviésemos añadiendo un proyecto a nuestra solución. Os voy a enseñar la estructura en un pequeño proyecto que hice:
De un vistazo vemos cómo se organiza nuestro proyecto y nos es muy fácil navegar por esta estructura y encontrar lo que buscamos. Pero para eso primero tenemos que seguir una estructura y no tirarlo todo al tuntun.
En este caso estaba siguiendo la Clean Architecture que ya vimos una introducción.
Esto también puede ser una arma de doble filo porque podemos acabar con tropecientos Assemblies y tampoco es bueno. Las cosas buenas en exceso pueden ser malas.
En este caso yo solo utilizo Assemblies para separar capas pero no módulos concretos del proyecto como podría ser el sistema de combate.
Si no os gusta esta vista simplemente podéis utilizar la vista de Unity por carpetas y los Assemblies os serán transparentes a la hora de navegar, pero como podéis ver seguimos manteniendo esta estructura:
Si sigues una buena estructura te será igual de fácil encontrar las cosas con una vista que con la otra.
Nos ayudan a forzar que se cumpla La regla de la Dependencia
Los assemblies también nos ayudan, o mejor dicho, nos ayudan a forzar que se cumpla la regla de la dependencia y evitar dependencias circulares.
Ya hablamos de esta regla hace algunos posts pero a modo de super resumen, la regla de la dependencia no es otra cosa que las flechas de relación entre clases sólo pueden ir en una dirección.
Si A conoce a B, B no puede conocer a A. Además si utilizamos una arquitectura por capas, como es la Clean Architecture que os he mostrado antes la estructura del proyecto, las capas de fuera pueden conocer a las de dentro, pero las de dentro NUNCA conocerán a las de fuera.
Si en el ejemplo que vimos al principio intento relacionar el Assembly de Entity con el de UseCase lo que tengo es el siguiente error: «Assembly with cyclic references detected».
Lo cual significa que tengo una referencia circular y que no está permitido. Y esto es mágico, gracias a esto podemos forzar que carpetas, o que partes de la estructura, puedan comunicarse con qué otras partes. Nos da total control de las relaciones de clases en nuestro proyecto.
En el caso de la Clean Architecture haríamos que nuestras entidades estuviesen aisladas de todo y no se acoplaran con nada, al mismo tiempo haríamos que la vista solo pudiera hablar con la capa más próxima y bajo ningún concepto permitiríamos a nuestro core hablar directamente con la vista.
Conclusiones
Los Assembly Definitions son un gran aliado de los tiempos de compilación y la reducción del tiempo de iteración cuando estamos programando. En proyectos medianos/grandes esto tiene una gran importancia ya que nadie quiere tener que esperar minutos para poder probar una línea de código.
Al mismo tiempo los Assemblies nos ayudan a definir las relaciones que tendrán nuestras clases y a hacer respetar una estructura como podría ser la Clean Architecture y La regla de la dependencia.
Todo esto lo conseguimos al pequeño coste de crear estas configuraciones al inicio del proyecto y ya lo tendremos preparado para siempre.
Además nos permitirán elegir si tenemos alguna parte del código que solo queremos que esté disponible en el editor, como son los cheats. No queremos que el usuario final pueda hacer trucos dentro de nuestro juego.
Otras entradas
- ¿Cómo empezar en el desarrollo de videojuegos?
- Patrones de diseño – Template Method
- Patrones de diseño – Service Locator
- Cómo aumentar el rendimiento de tu equipo en Unity
- Patrones de diseño – Composite
- Devlog #00 – Empezamos proyecto nuevo