genbetadev / Genbeta-Dev-Engine

Desarrollo de un Game Engine básico sobre C++ y SFML 2.1
MIT License
63 stars 32 forks source link

Organización del código #57

Closed rickyah closed 10 years ago

rickyah commented 10 years ago

Quería comentar un poco la organización de los ficheros de código en el filesystem, que la veo muy limitada, al parecer es la que usa por defecto Visual Studio.

Para empezar, dividir en dos directorios por headers y fuentes no me parece la mejor opción. Si la más cómoda a la hora de distribuir (copias el compilado, y luego el directorio de headers) pero a mi criterio lo lógico sería agrupaciones que tengan más sentido (después de todo si queremos distribuir los headers podemos hacer un script que los copie a otro directorio)

Por ejemplo, para los dos proyectos, el engine en si y el test, duplicamos la estructura de directorios:

/src/GDE/
/src/test/
/include/GDE
/include/test

Lo que propongo inicialmente es lo siguiente:

/GDE/src/
/GDE/include/

/test/src/
/test/include/

Así cada proyecto tendría sus propios ficheros, y sólo esos.

Incluso iría un paso más allá y organizaría los datos en el proyecto por modulos que tengan sentido juntos, por ejemplo, para el sistema de lob

/GDE/Core/Log/include/log.hpp
/GDE/Core/Log/src/log.cpp

Esto permitiría una navegación más sencilla en el momento en el que las cosas empiecen a crecer, que lo harán. También creo que, de hacerlo, lo mejor es hacerlo ahora que hay pocos ficheros.

adrigm commented 10 years ago

@rickyah Creo que tanto directorio no falicitaría la construcción con cmake. De todas formas la estructura de directorios de carpetas no tiene con coincidir con las carpetas virtuales de un determinado IDE que usemos.

¿Qué sentido tiene separar a nivel físico los headers de los ficheros fuente en un ejecutable? Ya digo que en el IDE sí está separados.

rickyah commented 10 years ago

@adrigm Sobre CMake no lo he usado, pero lo dudo. Precisamente para eso tenemos esas herramientas. Si CMake no es capaz de gestionar bien listas de ficheros y directorios sería un problema grave.

Sobre lo demás es una buena práctica mantener la misma estructura lógica y física. Los IDEs mantendrán esa estructura, pero entonces significa que para cada IDE que hagas tienes que organizar tu el código a mano. Además, no todo el mundo usa IDEs, si yo quiero programar en Subline/Emacs/Vim no puedo mantener una esa separación, y estoy forzado a la falta de estructura.

Ahora es más o menos fácil aclararse, pero cuando el número de ficheros crezca, hará más complicado que gente nueva entre en el proyecto.

german-e-a commented 10 years ago

Me gustaría que de ser posible que cambies el nombre del directorio bin por data por que para los que usamos unix el directorio bin es para ejecutables; Me parece ademas que con data es mas claro. Ej.:

.../bin/windows.cfg .../bin/data/Roboto.ttf

quedaría

.../data/confs/windows.cfg .../data/fonts/Roboto.ttf

adrigm commented 10 years ago

@german-e-a, es que bin es un directorio de ejecutable. Ahí es donde se crea el ejecutable de la aplicación de prueba window.cfg es el archivo que configura la ventana y debe estar en el mismo directorio que el ejecutable.

Data es el directorio donde irán los recursos que utilice el proyecto de prueba.

La idea de esto es que una vez completado el juego, el usuario tenga en el directorio bin su paquete para distribuir con su ejecutable y sus recursos.

rickyah commented 10 years ago

¿Y sobre la organización de los ficheros de código?

adrigm commented 10 years ago

@rickyah, yo no creo que el orden actual sea malo, muchas APIs se organizan con este estilo, para mi la forma que propones no aporta claridad, pero como siempre que decida la comunidad. A ver si alguien más da su opinión.

rickyah commented 10 years ago

Esta organización que indico es la que fuerza Java y recomienda C#. Es cierto que esos lenguajes no tienen el problema de dividir en dos ficheros la definición de símbolos, pero precisamente por eso es más importante en C++.

El problema es que visual studio no fuerza esa organización en c++ al mantener por motivos de compatibilidad una separación organizativa a nivel físico. Ahora con indicar que busque ficheros de forma recursiva está solucionado :)

Pero como dices, que decida la gente, es un cambio fácil ahora con pocos ficheros y con git, que un rebase ya lo tienes solucionado.

RdlP commented 10 years ago

A mi la organización que ha propuesto @rickyah me parece más clara que la actual

/GDE/src/
/GDE/include/

/test/src/
/test/include/

Se ve claramente que hay 2 proyectos y cada proyecto con su src e include, lo que no veo necesario es ir agrupando por módulos ya que (de momento) es un proyecto pequeño.

german-e-a commented 10 years ago

a mi también me parece mas claro es más to iría un paso mas allá y renombraria test y lo llamaría .../example/basic al estilo de organización de código de QT5/KF5. dado que seria mas claro mostrar distintos ejemplos progresivos en lugar de uno solo que muestre todas las áreas de la libreria; Es más trabajo pero me parece mas educativo.

rickyah commented 10 years ago

También os voy a contar que por mi experiencia lo de "ahora mismo el proyecto es muy sencillo, no merece la pena hacer X hasta más adelante" en general al final significa que no se hará en la vida xD

Por otro lado, estaría bien debatir si implementar el motor con TDD y meter algún framework como UnitTest++ para hacer pruebas. Si hacemos eso nuestro engine ya subiría +:100: niveles

adrigm commented 10 years ago

@rickyah, Sí, había pensado lo de meter test unitarios. Pero hay que ir con cuidado y tener en cuenta el objetivo del proyecto que es el aprendizaje.

Si se hace, que sea todo bien explicado para los no iniciados en pruebas unitarias y que sirva de aprendizaje para todos. Que por otra parte si se hace bien sería de un gran valor para que se entiendan las bases del desarrollo real.

rickyah commented 10 years ago

Yo se cómo van los tests unitarios y he hecho TDD, pero en C++ nunca hice nada de eso, la última vez que toqué c++ esto se empezaba a "poner de moda" :P Si te animas para que aprendamos cuenta con mi hacha :facepunch:

imasip commented 10 years ago

Buenas a todos, como ya he comentado en el blog me gustaria saber a modo de aprendizaje cual es la mejor forma de organizar la estructura de directorios de un proyecto, o si hay alguna base o requisitos que se deban cumplir. Tambien comentar que me parece más aclaratoria la estructura de directorios de @rickyah ya que se entiende mejor que hay dos proyectos separados dentro de una misma solución.

ficion commented 10 years ago

@RdlP Pienso igual, son dos proyectos distintos; queda algo raro cuando se les junta. Aparte, pensé lo mismo que @german-e-a, después de todo, puede que quizá después hagamos otros "tests", o ejemplos que van a ser distintos; muchos proyectos lo hacen así también.

adrigm commented 10 years ago

Bueno, veo que la mayoría estáis a favor de restructurar el proyecto. Vamos entonces a llegar a consenso de como debería ser la nueva y a defnir todos los elementos.

@rickyah, puedes exponer tu modelo de forma completa y partir de ahí para decidir?

rickyah commented 10 years ago

Ok, déjame darle una pensada. También quiero hacer unas pruebas con VStudio y xcode, a ver cómo se podría organizar el proyecto, pero la idea general es:

/[nombre_proyecto]/include
/[nombre_proyecto]/src

Pero, como digo, yo iría un paso más y haría

/[nombre_proyecto]/[modulo1]/include
/[nombre_proyecto]/[module1]/src
/[nombre_proyecto]/[modulo2]/include
/[nombre_proyecto]/[module2]/src

Os lo preparo un poco mejor dentro de un rato

ficion commented 10 years ago

@rickyah ¿Cómo modularemos el proyecto? Esa pregunta creo que es para un nuevo tema, de hecho...

rickyah commented 10 years ago

No tranquilo, sería algo como

/GDE/Core/
/GDE/Log/
german-e-a commented 10 years ago

bueno en mi fork (https://github.com/german-e-a/Genbeta-Dev-Engine/tree/Reorganization_Code) cree una nueva rama para mostrar como se reorganizaría el código, todavía voy a ver si no hago otros cambios. Ademas faltan hacer los cambios correspondientes en los distintos sistemas de construcción yo solo conozco un poco de cmake ¿quisiera saber si en los demás sistemas se pude hacer que al construir el proyecto se haga en otro directorio al estilo Genbeta-Dev-Engine-build? y ¿si también tienen la capacidad de copiar al directorio los includes(*.hpp) de esta forma podríamos poner tanto los archivos cpp y hpp en la misma carpeta y solo cuando se genere el proyecto se crearía la carpeta include con los archivos correspondientes?

adrigm commented 10 years ago

@german-e-a, un par de cosas para esta organización. Tú haces:

/GDE/Core/include/GDE/Core/ /GDE/Core/include/GDE/Core.hpp /GDE/Core/include/GDE/Config.hpp

Tanto Core.hpp como Config.hpp no pertenecen al módulo Core, sino al proyecto en general. En concreto Core se encarga de incluir todos los headers del módulo Core para que en producción solo haga falta incluir un archivo al estilo SFML.

Por otro lado Config.hpp es el archivo de configuración del Engine que contiene macros importantes como GDE_API, GDE_DEBUG y la versión de la biblioteca. Por lo que debe ser accesible para todos los módulos.

Si se va a hacer de esta forma, yo creo que lo correcto sería:

/GDE/include/Config.hpp /GDE/include/Core.hpp /GDE/include/Core/ /GDE/include/OtroModulo.hpp /GDE/include/OtroModulo/

Donde OtroModulo es un ejemplo de nuevos módulos. Ademas tendriamos todos los includes en GDE/include/

german-e-a commented 10 years ago

Al principio el include lo moví como vos decís pero después recordé que en KF5(KDE framework 5) con cmake y QT5 con qmake ya no existe el directorio include y cmake o qmake se encarga de copiarlos a la carpeta include al generar el proyecto, dado que los .hpp estan en el mismo dir que los .cpp el código quedaría mas legible y moderno. por eso el commit es parte 1 porque dependiendo de las capacidades de los demás IDEs podríamos reorganizar el código los únicos dir que estarían decididos serian GDE y example

adrigm commented 10 years ago

En general no habría problema con mezclar los includes con los cpp ya que para crear las versiones de distrubución usaríamos cmake que permite el copiado de archivos. Pero que hacemos con los includes comunes que no pertenecen a ningún módulo?

Por cierto, tienes el proyecto para qmake o qtcreator? Sería interesante disponer de ellos.

german-e-a commented 10 years ago

Supongo que lo que sea compartido deberíamos mover los a una carpeta common o shared(QT), en cuanto a QTCreator puede leer los proyectos en cmake así que no habría problemas para este IDE.

rickyah commented 10 years ago

Yo también estaba intentando organizarlo por módulos separados, y da algún quebradero de cabeza, pero sobre todo a la hora de desarrollar en varios sistemas.

Por ejemplo, habría que definir dónde dejar cada uno de los diferentes elementos del engine. Por ejemplo, el engine en si mismo es una librería, supongo que iría en /lib, y ahí es donde la puse yo en Xcode. Eso nos lleva al siguiente problema: si añadimos cosas nuevas hay que añadirlo para cada entorno de desarrollo (Visual Studio, XCode, CodeLite, etc) así que creo que si realmente se quiere hacer multiplataforma habría que dejar bien preparado un CMake y aprender a usarlo para poder agregar nuevos proyectos.

Más cosas, yo a core.hpp lo llamaría GDE.hpp, ya que en realidad es el encabezado base para el engine. Yo también lo confundí como algo que era parte de Core :P

Por último, para incluir encabezados propios de nuestra propia librería yo suelo usar comillas. Creo que dependía del compilador, pero a no ser que haya cambiado, tanto VStudio como gcc consideraban que #include "header" era para liberías del proyecto en curso, y e #include <header> para librerías de sistema (consideradas externas, quiero decir) ¿Hay alguna motivación en usar siempre <>?

Esta noche muestro mi propuesta que ahora hay que trabajar

adrigm commented 10 years ago

@rickyah, se llama Core.hpp y no GDE.hpp porque son los includes del módulo Core no del engine en general. Algo parecido a SFML que se incluyen solo los módulos que se necesitan.

Por otra parte el uso <> es para indicar que se están usando incldes de algún path establecido y no de donde se encuentran los cpp.

rickyah commented 10 years ago

@adrigm de acuerdo con lo de core.hpp

Lo de los includes lo decía por que lo normal es usar "" para los ficheros del propio proyecto. De hecho el comportamiento de ambos formatos es casi el mismo: con comillas busca antes en los paths locales y si aún así no encuentra el fichero entonces se comporta como si hubieras usado <>

http://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html http://msdn.microsoft.com/en-us/library/36k2cdd4(v=vs.110).aspx

imasip commented 10 years ago

Entonces como queda finalmente la estructura de directorios? Si alguien puede explicar exactamente que contiene cada parte de la estructura se lo agradecería.

rickyah commented 10 years ago

A ver, esta es mi proposición de estructura de directorios, es un punto intermedio que creo que es más organizado.

Todo el código tiene el siguiente layout físico: src/SUBSYSTEM1/include/LAYOUT_HEADERS_SUBSYSTEM1 src/SUBSYSTEM1/source/LAYOUT_SOURCES_SUBSYSTEM1

Para que veáis un ejemplo, esta es la forma que tiene ahora mi proyecto: project layout

¿Comentarios o dudas?

adrigm commented 10 years ago

El Core.pp lo sacaría de la carpeta del Core, se supone que representa todo lo que está en esa carpeta.

Sinceramente dentro de Core no haría tanta carpeta para App, Log, etc. La mayoría tendrán a lo sumo 3 - 4 archivos. ¿Que se supone que aporta en la estructura física tanta subcarpeta? Opinión personal como siempre.

desclapez commented 10 years ago

Opino igual que @adrigm, yo creo que es una etapa bastante temprana para reorganizar en tanta carpeta y ahora mismo no está tan claro que por ejemplo Log tenga que ir en una carpeta y App en otra.

Si supiéramos desde ya qué es lo que se va a hacer/incluir en el proyecto (clases, funcionalidades) arrojaría algo de luz en ese sentido, yo por supuesto estoy un poco a la espera de ver qué es lo que vamos a hacer porque nuncha he hecho un juego.

Veamos como avanza el proyecto y la separación quedará mas clara. Por ahora me basta con la separación de tests y source.

rickyah commented 10 years ago

Entiendo que ahora mismo no parece importante, pero por experiencia es mejor tenerlo organizado. Efectivamente es poco para organizar, pero sólo hay que hacerlo una vez, tampoco cuesta tanto, pero bueno, si luego al final si se hace, me parece bien :)

Lo que si que yo haría es separar Log y Utils de Core, ya que son claramente módulos separados.

desclapez commented 10 years ago

No confundamos módulos con organización, el core no puede tener dependencias con otros módulos. Está bien separar clases por tener una función distinta pero por ejemplo el Log es usado en el core intensivamente.

Ah, sobre el tema de los nombres de las clases, a mi me gustaría algo así:

src: Core/App.cpp Core/Config.cpp Core/Director.cpp (SceneManager) Core/Log.cpp Core/Scene.cpp Core/Resource.cpp Core/ResourceManager.cpp Core/StringUtil.cpp

include: Core/Types.cpp ...

Lo de Director es simplemente que hay engines que utilizan este nombre en lugar de SceneManager, es una idea. Types en lugar de CoreTypes por limpieza. Y config quizás pueda meterse en una clase que sea capaz de leer la configuración que salva, el config create digamos que es como una utilidad para añadir lineas a un fichero de configuración.

Como lo veis?

rickyah commented 10 years ago

¿Quién dice que el Core no puede tener dependencias con otros módulos? Claro que puede: si son módulos externos comunes. Core usará el log extensivamente, pero el resto de los módulos que vayamos a usar también van a usar el Log también extensivamente.

Yo creo que Scene Manager es más concreto. Director es muy genérico y mucho menos claro, aunque sea el nombre que usa Cocos :P

Types yo creo que también sería bueno renombrarlo por limpieza, como dice @titoneo

angelnavarro commented 10 years ago

Yo pienso igual que @adrigm y @titoneo , ahora mismo mantenerlo simple y, en caso de modularizar, lo haría más adelante.

desclapez commented 10 years ago

Es que me ha gustado el nombre de Director, jeje. Es por no abusar del sufijo manager, aunque es cierto que SceneManager queda muy claro. Esto de los nombres para mí es una obsesión, ya os habréis dado cuenta :)

@rickyah sobre el log yo lo veo tan arraigado que puede ir sin problema en el core, al menos de momento, al igual que las utils o helpers de conversiones, podrían ir en una carpeta por tema de separar un poco las clases pero ya está. Al fin y al cabo los módulos o extensiones que se hagan dependerán de core. El día en que haga falta y se haga será el momento idóneo y ya verás como no es tanto trabajo.

rickyah commented 10 years ago

Yo te digo mi experiencia: Supongamos que llega un momento que todo crece y decidimos separar el log de core, por poner un ejemplo. La consecuencia es que tendrás que ir por cada translation unit, para cambiar o añadir la nueva referencia al include del Log. No será bonito :hurtrealbad: Vale que probablemente me he pasado con carpetas en app y tal, eso si, pero separar utils y log me parece que está bien hacerlo ahora.

Los nombres para mi también es algo importantísimo y que mucha gente considera como algo que no es muy relevante, lamentablemente. Creo que lo importante es más nuestra convención. Me refiero, si usamos Manager como nombre de algo, eso tiene que significar siempre una cosa. Por ejemplo, que se refiera a algo que gestiona a más alto nivel otras estructuras, que quizá signifique que está implementado como un singleton (o que sólo debe haber una instancia), pero que signifique lo que signifique, que haya una consistencia, de forma cada vez que leamos algo como FooManager sepamos que es un singleton que va a gestionar Foos. Esto son ejemplos, no se si se entiende lo que quiero decir, o si estáis de acuerdo.

adrigm commented 10 years ago

A mi modo de ver no tiene sentido separar el Log del Core ya que es parte del mismo. Cuando se implementen otros módulos la idea es crear una dependencia con Core. Que core sea el módulo que implemente todas las utilidades y clases necesarias.

Algo parecido a lo que sucede en SFML, donde el módulo System es necesario para usar otros módulos ya que tiene clases como NoCopiable o Error.

Si por ejemplo implementamos un módulo de Física necesitare acceso al Log, a la clase App, etc... Lo mismo para un módulo de GUI.

rickyah commented 10 years ago

El log es el elemento más acoplado de un proyecto, por que se usa en todos los sistemas, pero a su vez está desacoplado por que podría considerarse que no es parte del sistema. Prueba de ello que es es más que común usar una librería externa para gestionar el logging. Es más una dependencia que otra cosa, de ahí que también sea una GRAN idea logear siempre con macros, por que así además nos sirven de una especie de interface, que nos permitiría cambiar el log si fuera necesario.

Lo que te debes preguntar es si todos los módulos que vamos a crear realmente necesitaran todo lo que hay en Core, por que si no es así cuando creemos un módulo en el que queramos logear algo, podemos estar estableciendo dependencias que no necesita. Por ejemplo, ¿todos los módulos van a necesitan cargar una configuración de fichero? ¿Y escribirla? Si añadimos más cosas a Core, es suma y sigue.

imasip commented 10 years ago

El ultimo planteamiento que realiza @rickyah https://github.com/rickyahes bastante acertado creo yo. Visto esto, yo tambien soy partidario de separar Log y Utils de Core.

El 14 de noviembre de 2013 11:52, Ricardo Amores Hernández < notifications@github.com> escribió:

El log es el elemento más acoplado de un proyecto, por que se usa en todos los sistemas, pero a su vez está desacoplado por que podría considerarse que no es parte del sistema. Prueba de ello que es es más que común usar una librería externa para gestionar el logging. Es más una dependencia que otra cosa.

Lo que te debes preguntar es si todos los módulos que vamos a crear realmente necesitaran todo lo que hay en Core, por que si no es así cuando creemos un módulo en el que queramos logear algo, podemos estar estableciendo dependencias que no necesita. Por ejemplo, ¿todos los módulos van a necesitan cargar una configuración de fichero? Y si añadimos más cosas a Core, es suma y sigue.

— Reply to this email directly or view it on GitHubhttps://github.com/genbetadev/Genbeta-Dev-Engine/issues/57#issuecomment-28474939 .

desclapez commented 10 years ago

@rickyah mira lo de la macro para el log me parece genial! Así tendríamos en lugar de esto:

GDE::Log::info("App::createWindow", "Ventana creada");

esto:

LOGI("App::createWindow", "Ventana creada");

Incluso esto con el tag "info" por defecto:

LOGI("Ventana creada");

Con las correspondientes 4 funciones: LOGI LOGD LOGE LOGW

Además para los distinos perfiles de compilación, en la compilación sin log simplemente no metería código y nos ahorraríamos todas las llamadas a funciones vacías : )

Esto está ya?

rickyah commented 10 years ago

Lo de la macro creo que ya estaba hablado: https://github.com/genbetadev/Genbeta-Dev-Engine/issues/67

desclapez commented 10 years ago

Ya decía yo que me sonaba xD

imasip commented 10 years ago

a ver si podéis resolverme una duda que me surge... Porque el código fuente los .cpp y los .hpp están dentro de los projects (GDE.workspace por ejemplo), y después también esta en las carpetas include y src fuera del project? que sentido tiene?

2013/11/14 Diego Esclapez notifications@github.com

Ya decía yo que me sonaba xD

— Reply to this email directly or view it on GitHubhttps://github.com/genbetadev/Genbeta-Dev-Engine/issues/57#issuecomment-28479370 .

adrigm commented 10 years ago

@imasip No he entendido a que te refieres.

rickyah commented 10 years ago

Los proyectos en cada IDE definen una estructura lógica que no tiene por qué coincidir con la estructura física. Es decir, que en el IDE ordenas los ficheros de manera distinta a cómo los ordenas en el disco duro, no se si me explico.

Siento haber estado desaparecido, pero ya tengo un poco más de tiempo disponible.

imasip commented 10 years ago

@adrigm siento no haber podido contestar antes, pero con la respuesta de @rickyah ya queda despuejada mi duda. Muchas gracias!

rickyah commented 10 years ago

Al final ¿vamos a usar la nueva organización de código? Lo digo por ir actualizando la rama master y poder continuar con el resource manager a partir de una base de código común. Acabo de hacer un rebase de master y tengo que arreglar todos los conflictos, pero si al final no lo vamos a cambiar es trabajar "pa na".

Si se cambia además necesitaré que alguien más compruebe que el proyect funciona bien en alguna plataforma, por que no lo he probado nada más que en xcode (tengo pendiente instalar la última versión del Visual Studio)

adrigm commented 10 years ago

@rickyah Sí, parece que estamos de acuerdo todos en cambiarlo. Con los cambios todas las soluciones de proyectos existentes dejarán de funcionar. Creo que es hora de plantearnos usar solamente Cmake y que cada uno luego mantenga el IDE de su conveniencia.

Yo me encargo de probarlo en Visual Studio.

rickyah commented 10 years ago

Había visto hace tiempo un proyecto que generaba automáticamente los ficheros de solución/proyecto para varios IDEs, que no pintaba mal. Voy a buscarlo.

Sin embargo, usar CMake es de momento la mejor solución, mi único problema es que no se usarlo :worried: Me miraré un buen tutorial

Creo que visual studio permitía crear un proyecto usando un script externo de build, pero eso si puedes confírmalo tu @adrigm que estás más suelto en Visual Studio para c++. En Xcode si se puede, lo he visto pero no lo he configurado. Es más que probable que el resto de IDEs que se usan tengan aún mejor soporte para CMake al estar más especializados en C++.

rickyah commented 10 years ago

Me pongo entonces a hacer el merge de la muerte, voy a hacer antes una lista de ficheros que cambiarán y la pongo aquí :+1: