Patrones de diseño modular en C -- ampo con design-patterns campo con modules camp codereview Relacionados El problema

Modular Design Patterns in C


4
vote

problema

Español

He creado un patrón de diseño modular que proporciona una única interfaz que se puede usar crear instancias con componentes de back-end canalizables, sin embargo, no estoy completamente satisfecho con él.

Mi implementación práctica implica crear una interfaz genérica a ciertos tipos de controladores de dispositivos. La esperanza es que pueda crear una interfaz que expone una capa significada como un adaptador (para inicializar a los conductores que no se ajustan a las implementaciones de conformidad) y para mencionar la infraestructura marco.

Para acercar el enfoque al patrón de diseño en sí, estoy mostrando un ejemplo simplificado.

El código fuente se puede encontrar aquí .

Digamos que tengo alguna aplicación con un main.c así:

  #include <stdio.h> #include <stdlib.h> #include "boatModuleIF.h"  int main(int argc, char *argv[]) {      char *type = argv[1];     int typeNum = atoi(type);      moduleIF_t *IF = init_moduleIF(typeNum);      if (IF) {         IF->printCfg(IF->ctx);     }     else {         printf("Failed to init module");     }      return 0; }   

Yo uso BoatmoduleifDefs como un encabezado que es común a todos los productos básicos (es decir, en Beatmodule, Boatmoduleif, CNC, Beneteau)

expone lo siguiente a esos componentes: boatmoduleifdefs.h

  #ifndef __MODULEIFDEFS_H_ #define __MODULEIFDEFS_H_  typedef struct moduleIF_CTX *moduleIF_CTX_t;  typedef struct {     void (*printCfg)(moduleIF_CTX_t ctx);      moduleIF_CTX_t ctx; } moduleIF_t;  __attribute__((weak)) extern moduleIF_t *init_moduleIF_CNC(); __attribute__((weak)) extern moduleIF_t *init_moduleIF_Beneteau();  #endif // __MODULEIFDEFS_H_    

Tenga en cuenta que la función INIT para las interfaces del módulo CNC y Beneteau se declara como símbolos débiles. Esto significa que este código genérico puede exponer un símbolo que puede no definirse. Esto se usa como un proxy para determinar si nuestra aplicación se ha compilado con el "controlador" CNC.C.

con el encabezado y la fuente de BoatModuleif implementados como:

boatmoduleif.h

  #ifndef __TESTMODULEIF_H_ #define __TESTMODULEIF_H_ #include "boatModuleIFDefs.h"  enum {     TYPE_CNC = 0,     TYPE_BENETEAU, };  moduleIF_t *init_moduleIF(int type);  #endif // __TESTMODULEIF_H_    

boatmoduleif.c

  #include <stdlib.h> #include <stdio.h> #include <stdint.h> #include "boatModuleIFDefs.h" #include "boatModuleIF.h"  moduleIF_t *init_moduleIF(int type) {     switch (type) {         case TYPE_CNC:             if (init_moduleIF_CNC) {                 return init_moduleIF_CNC();             }             else {                 printf("failed cnc");                 return 0;             }             break;         case TYPE_BENETEAU:             if (init_moduleIF_Beneteau) {                 return init_moduleIF_Beneteau();             }             else {                 printf("failed ben");                 return 0;             }             break;         default:             return 0;     } }   

BoatModule también tiene un archivo DEFS que parece:

  #ifndef __TESTMTRDEFS_H_ #define __TESTMTRDEFS_H_  #include <stdbool.h> #include <stdint.h> #include <stdlib.h>  typedef struct {     uint8_t  size;     uint8_t  speed; } boatCfg_t;  __attribute__((weak)) extern boatCfg_t dfltBoatCfg;  #endif // __TESTMTRDEFS_H_    

Tenga en cuenta que el DFLTBOATCFG se define como un símbolo débil similar a nuestras funciones de inicio. Esto es útil si tenemos múltiples tipos de configuraciones que pueden no ser aplicables a todos los veleros.

Encabezado y fuente de BoatModule implementados como:

boatmodule.h

  #ifndef __TESTMODULE_H_ #define __TESTMODULE_H_ #include "boatModuleIFDefs.h"  moduleIF_t *init_moduleIF();  #endif // __TESTMODULE_H_    

boatmodule.c

  #include <stdlib.h> #include <stdio.h> #include <stdint.h> #include "boatModuleIFDefs.h" #include "boatModule.h" #include "boatModuleDefs.h"  struct moduleIF_CTX {     uint8_t size;     uint8_t speed; };  static void printCfg(moduleIF_CTX_t ctx) {     printf("speed %d size %d", ctx->speed, ctx->size); }  moduleIF_t *init_moduleIF() {     struct moduleIF_CTX * const CTX = calloc(1, sizeof(struct moduleIF_CTX));      if (&dfltBoatCfg) {         CTX->size = dfltBoatCfg.size;         CTX->speed = dfltBoatCfg.speed;     }      moduleIF_t * const IF = (moduleIF_t *) calloc(1, sizeof(moduleIF_t));     IF->ctx = CTX;     IF->printCfg = printCfg;     return IF; }    

Luego, tenemos dos archivos de origen para dos implementaciones diferentes deómetro de barco (que aquí están un stand-in para los conductores)

cnc.c

  #include "boatModuleDefs.h"  boatCfg_t dfltBoatCfg = {     .size = 10,     .speed= 10, };    

BENETEAUN.C

  #include "boatModuleDefs.h"  boatCfg_t dfltBoatCfg = {     .size = 5,     .speed= 5, };    

La parte interesante (IMHO) está realmente en el Makefile, sin embargo.

makefile

  all: joinedModules  joinedModules: boatModule_Cnc.o boatModule_Beneteau.o boatModuleIF.o boatModuleDefs.h     gcc boatModuleIF.o boatModule_Cnc.o boatModule_Beneteau.o main.c -o getBoatCfg  boatModuleIF.o:     gcc -c boatModuleIF.c  boatModule_Beneteau.o: boatModule.o beneteau.o boatModuleDefs.h     ld -r beneteau.o boatModule.o -o boatModule_Beneteau.o     objcopy --redefine-sym printCfg=printCfg_Beneteau boatModule_Beneteau.o     objcopy --redefine-sym init_moduleIF=init_moduleIF_Beneteau boatModule_Beneteau.o     objcopy --redefine-sym dfltBoatCfg=dfltBoatCfg_Beneteau boatModule_Beneteau.o  boatModule_Cnc.o: boatModule.o cnc.o boatModuleDefs.h     ld -r cnc.o boatModule.o -o boatModule_Cnc.o     objcopy --redefine-sym printCfg=printCfg_CNC boatModule_Cnc.o     objcopy --redefine-sym init_moduleIF=init_moduleIF_CNC boatModule_Cnc.o     objcopy --redefine-sym dfltBoatCfg=dfltBoatCfg_CNC boatModule_Cnc.o  boatModule.o: beneteau.o cnc.o boatModuleDefs.h     gcc -c -fPIE boatModule.c  cnc.o: boatModuleDefs.h     gcc -c -fPIE cnc.c  beneteau.o: boatModuleDefs.h     gcc -c -fPIE beneteau.c   

Esencialmente lo que estoy haciendo es fusionar tanto el archivo de objeto del módulo como un componente de backend juntos para crear un nuevo archivo de objeto fusionado. Luego, puedo redefinir los símbolos globales utilizados por ambos para prevenir las colisiones de símbolos de tal manera que mantenga la "simplicidad" de los archivos de interfaz genéricos del módulo.

Esto tiene algunos beneficios, especialmente:

  • Durante la inicialización de la interfaz, no necesito un caso de conmutación desordenada, lo que tendría que verificar si cada tipo de la embarcación tiene cada tipo de configuración de barco.
  • apoya la reutilización del código.
  • Si quiero agregar nuevas configuraciones, hay poco que se necesita agregar (excepto una instrucción SI adicionales en el ModuleiF Init y la definición en el barco / controlador que realmente se preocupa por esa configuración).
  • Si quiero agregar un nuevo barco, todo lo que necesito es agregar un nuevo símbolo débil de init y algunos ajustes al makefile (realmente simplemente agregar el nombre de la fuente, el resto se podría hacer automáticamente con las reglas)

El problema es que esto no se ha callado se siente bien y me pregunto si es un tipo de código olor ?

Podría evaluar el código mucho más difícil (por ejemplo, no he definido ningún símbolo llamado DFLTBOATCFG, se redefinió como DFLTBOATCFG_CNC y DFLTBOATCFG_BENETEAU) Sin embargo, esto podría mitigarse con buenos comentarios / documentación.

Si es así, hay algún enfoque mejor / modificado que pueda tomar, me permitiría crear este tipo de patrón de diseño modular que es un futuro impermeable contra el infierno de mantenimiento en caso de que debamos respaldar muchos tipos de barcos con muchas configuraciones diferentes ?

CUALQUIER CUALQUIER COMENTARIO ES MUCHO APRECIADA.

Original en ingles

I have created a modular design pattern which provide a single interface that can be used create instances with swapable back-end components, however I'm not entirely satisfied with it.

My practical implementation involves creating a generic interface to certain kinds of device drivers. The hope is that I can create an interface which exposes a layer meant as an adapter (for initializing drivers which non-interface conforming implementations) and to bring up framework infrastructure.

To bring focus to the design pattern itself I am showing a simplified example.

The source code can be found here.

say I have some application with a main.c like so:

#include <stdio.h> #include <stdlib.h> #include "boatModuleIF.h"  int main(int argc, char *argv[]) {      char *type = argv[1];     int typeNum = atoi(type);      moduleIF_t *IF = init_moduleIF(typeNum);      if (IF) {         IF->printCfg(IF->ctx);     }     else {         printf("Failed to init module");     }      return 0; } 

I use boatModuleIFDefs as a header which is common to all boatModuleComponents (i.e. boatModule, boatModuleIF, cnc, beneteau)

It exposes the following to those components: boatModuleIFDefs.h

#ifndef __MODULEIFDEFS_H_ #define __MODULEIFDEFS_H_  typedef struct moduleIF_CTX *moduleIF_CTX_t;  typedef struct {     void (*printCfg)(moduleIF_CTX_t ctx);      moduleIF_CTX_t ctx; } moduleIF_t;  __attribute__((weak)) extern moduleIF_t *init_moduleIF_CNC(); __attribute__((weak)) extern moduleIF_t *init_moduleIF_Beneteau();  #endif // __MODULEIFDEFS_H_  

Note that the init function for the CNC and Beneteau module interfaces are declared as weak symbols. This means that this generic code can expose a symbol which may or may not be defined. This is used as a proxy to determine whether our application has been compiled with the cnc.c "driver".

with boatModuleIF's header and source implemented as:

boatModuleIF.h

#ifndef __TESTMODULEIF_H_ #define __TESTMODULEIF_H_ #include "boatModuleIFDefs.h"  enum {     TYPE_CNC = 0,     TYPE_BENETEAU, };  moduleIF_t *init_moduleIF(int type);  #endif // __TESTMODULEIF_H_  

boatModuleIF.c

#include <stdlib.h> #include <stdio.h> #include <stdint.h> #include "boatModuleIFDefs.h" #include "boatModuleIF.h"  moduleIF_t *init_moduleIF(int type) {     switch (type) {         case TYPE_CNC:             if (init_moduleIF_CNC) {                 return init_moduleIF_CNC();             }             else {                 printf("failed cnc");                 return 0;             }             break;         case TYPE_BENETEAU:             if (init_moduleIF_Beneteau) {                 return init_moduleIF_Beneteau();             }             else {                 printf("failed ben");                 return 0;             }             break;         default:             return 0;     } } 

boatModule also has a defs file which looks like:

#ifndef __TESTMTRDEFS_H_ #define __TESTMTRDEFS_H_  #include <stdbool.h> #include <stdint.h> #include <stdlib.h>  typedef struct {     uint8_t  size;     uint8_t  speed; } boatCfg_t;  __attribute__((weak)) extern boatCfg_t dfltBoatCfg;  #endif // __TESTMTRDEFS_H_  

Note that the dfltBoatCfg is defined as a weak symbol similarily to our init functions. This is useful if we have multiple kinds of configurations that may not be applicaple to all sailboats.

boatModule's header and source implemented as:

boatModule.h

#ifndef __TESTMODULE_H_ #define __TESTMODULE_H_ #include "boatModuleIFDefs.h"  moduleIF_t *init_moduleIF();  #endif // __TESTMODULE_H_  

boatModule.c

#include <stdlib.h> #include <stdio.h> #include <stdint.h> #include "boatModuleIFDefs.h" #include "boatModule.h" #include "boatModuleDefs.h"  struct moduleIF_CTX {     uint8_t size;     uint8_t speed; };  static void printCfg(moduleIF_CTX_t ctx) {     printf("speed %d size %d", ctx->speed, ctx->size); }  moduleIF_t *init_moduleIF() {     struct moduleIF_CTX * const CTX = calloc(1, sizeof(struct moduleIF_CTX));      if (&dfltBoatCfg) {         CTX->size = dfltBoatCfg.size;         CTX->speed = dfltBoatCfg.speed;     }      moduleIF_t * const IF = (moduleIF_t *) calloc(1, sizeof(moduleIF_t));     IF->ctx = CTX;     IF->printCfg = printCfg;     return IF; }  

Then we have two source files for two different boatModule implementations (which here are a stand-in for drivers)

cnc.c

#include "boatModuleDefs.h"  boatCfg_t dfltBoatCfg = {     .size = 10,     .speed= 10, };  

beneteau.c

#include "boatModuleDefs.h"  boatCfg_t dfltBoatCfg = {     .size = 5,     .speed= 5, };  

The interesting part (imho) is really in the makefile however.

makefile

all: joinedModules  joinedModules: boatModule_Cnc.o boatModule_Beneteau.o boatModuleIF.o boatModuleDefs.h     gcc boatModuleIF.o boatModule_Cnc.o boatModule_Beneteau.o main.c -o getBoatCfg  boatModuleIF.o:     gcc -c boatModuleIF.c  boatModule_Beneteau.o: boatModule.o beneteau.o boatModuleDefs.h     ld -r beneteau.o boatModule.o -o boatModule_Beneteau.o     objcopy --redefine-sym printCfg=printCfg_Beneteau boatModule_Beneteau.o     objcopy --redefine-sym init_moduleIF=init_moduleIF_Beneteau boatModule_Beneteau.o     objcopy --redefine-sym dfltBoatCfg=dfltBoatCfg_Beneteau boatModule_Beneteau.o  boatModule_Cnc.o: boatModule.o cnc.o boatModuleDefs.h     ld -r cnc.o boatModule.o -o boatModule_Cnc.o     objcopy --redefine-sym printCfg=printCfg_CNC boatModule_Cnc.o     objcopy --redefine-sym init_moduleIF=init_moduleIF_CNC boatModule_Cnc.o     objcopy --redefine-sym dfltBoatCfg=dfltBoatCfg_CNC boatModule_Cnc.o  boatModule.o: beneteau.o cnc.o boatModuleDefs.h     gcc -c -fPIE boatModule.c  cnc.o: boatModuleDefs.h     gcc -c -fPIE cnc.c  beneteau.o: boatModuleDefs.h     gcc -c -fPIE beneteau.c 

Essentially what I am doing is merging both the module object file and a backend component together to create a new merged object file. I can then redefine the global symbols used by both to prevent symbol collisions in such a way that maintains the "simplicity" of the generic module interface files.

This has some benefits, notably:

  • During initialization of the interface I don't need some messy switch case which would have to check whether each type boat has each kind of boat config.
  • Supports code reuse.
  • If I want to add new configuration's there's little that needs to be added (except for one addtional if statement in the moduleif init and the definition in the boat/driver that actually cares about that config).
  • If I want to add a new boat then all I need is to add a new init weak symbol and some tweaks to the makefile (really just adding the source name, the rest could be done automatically with make rules)

The issue is this doesn't quiet feel right and I'm wondering if this is some kind of code smell?

It could make evaluating the code much more difficult (e.g. I have not defined any symbol named dfltBoatCfg, it's redefined as dfltBoatCfg_CNC and dfltBoatCfg_Beneteau) however this could be mitigated with good comments/documentation.

If so is there some better/modified approach I could take would allow me to create this kind of modular design pattern that is future proofed against maintanence hell in the event that we should have to support many types of boats with many different configurations?

Any and all feedback is much appreciated.

        
   
   

Lista de respuestas

4
 
vote
vote
La mejor respuesta
 

No oculte los punteros

No oculte los punteros en un Typedef:

  typedef struct moduleIF_CTX *moduleIF_CTX_t;   

Esto hace que sea realmente difícil detectar cuando las cosas se pasan por valor o por puntero en el resto del código. Podrías hacerlo más explícito:

  typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t;   

pero solo haría esto:

  typedef struct moduleIF_CTX moduleIF_CTX;   

Sí, usted puede typedef3 A struct a su propio nombre, y hace lo que desea. Y ahora puedes usar esto de la siguiente manera:

  typedef struct {     void (*printCfg)(moduleIF_CTX *ctx);     moduleIF_CTX *ctx; } moduleIF;   

Es un poco menos que escribir y más explícito al mismo tiempo.

Considere usar un registro creado dinámicamente para los módulos

El principal inconveniente de su enfoque es tener que cambiar init_moduleIF() cada vez que agregue o quite un módulo. Sería mejor si los módulos podrían registrarse de alguna manera en una matriz o en la lista. Una forma de hacerlo es para escribir funciones que se llaman en el inicio del programa y / o el tiempo de carga de la biblioteca. Estas son funciones que entran en una sección de enlazador dinámico especial. Cómo obtener funciones No existe C, pero con GCC al menos puede usar 9988777665544337 para marcar una función que tiene que ejecutarse antes de 99887776655443388 . Aquí hay un ejemplo de cómo se podría usar. Primero, asegúrese de moduleIF contiene su identificador de tipo, y un puntero al siguiente typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t; 0 :

  typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t; 1  

Añada una variable global que contiene un puntero al primer módulo, y cree una función para agregar nuevos módulos a esa lista:

  typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t; 2  

Luego, en un módulo en sí, como typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t; 3 , do:

  typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t; 4  

Si ahora vincula módulos múltiples en un solo binario, entonces todas sus funciones de constructor se llamarán antes de typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t; 5 se inicia, por lo que en ese momento 99887776655443316 será un vinculado Lista que contiene todas las definiciones de la interfaz del módulo registrado. A continuación, puede cambiar typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t; 7 a:

  typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t; 8  

Acerca del uso de símbolos débiles y renombrados

Creo que este enfoque es menos flexible que el que describí anteriormente. Además, si lo sabe en el tiempo de compilación, ¿qué 99887766555443319 va a enlazar juntos, en lugar de usar símbolos débiles, también puede compilar typedef struct moduleIF_CTX moduleIF_CTX; 0 con typedef struct moduleIF_CTX moduleIF_CTX; 1 < / Código> Si sabe que el módulo CNC no está compilado, o definir otra cosa y usar otra cosa y usar typedef struct moduleIF_CTX moduleIF_CTX; 2 S dentro typedef struct moduleIF_CTX moduleIF_CTX; 3 Para compilar solo a los typedef struct moduleIF_CTX moduleIF_CTX; 4 s que son válidos. Creo que eso es tan bonito (o feo, dependiendo de lo que piensas de ello) como usando símbolos débiles, excepto que se basa menos en trucos de enlazadores.

En cuanto al cambio de nombre de los símbolos, esto también es innecesario. typedef struct moduleIF_CTX moduleIF_CTX; 5 es typedef struct moduleIF_CTX moduleIF_CTX; 6 , y typedef struct moduleIF_CTX moduleIF_CTX; 7 solo pondrá un puntero a esta versión local de typedef struct moduleIF_CTX moduleIF_CTX; 8 en el typedef struct moduleIF_CTX moduleIF_CTX; 9 que se devuelve.

Necesita cambiar el nombre typedef0 , porque, de lo contrario, solo de las instancias typedef1 sobrevive a la vinculación débil. Pero si no cambias el nombre de ese símbolo, compilará y vinculará sin errores.

Otra forma de resolver este problema es no hacer ningún tipo de cambio de cambio de símbolo, y no tener 99887776655443332 vinculado en varias veces. En su lugar, víncelo una vez en el binario final, y haga que tome un argumento de puntero que se puede usar para apuntar a un 998877665554433333

  typedef4  

y, por ejemplo, en typedef5 , escriba:

  typedef6  

Es solo unas pocas líneas extra, pero ahora puedo ver qué sucede al mirar la fuente, en lugar de tener que entender su sistema de compilación también. Este enfoque también es más portátil.

 

Don't hide pointers

Don't hide pointers in a typedef:

typedef struct moduleIF_CTX *moduleIF_CTX_t; 

This makes it really hard to spot when things are passed by value or by pointer in the rest of the code. You could make it more explicit:

typedef struct moduleIF_CTX *moduleIF_CTX_ptr_t; 

But I would just do this:

typedef struct moduleIF_CTX moduleIF_CTX; 

Yes, you can typedef a struct to its own name, and it does what you want. And now you can use this as follows:

typedef struct {     void (*printCfg)(moduleIF_CTX *ctx);     moduleIF_CTX *ctx; } moduleIF; 

It's both a bit less to type and more explicit at the same time.

Consider using a dynamically created registry for modules

The main drawback of your approach is having to change init_moduleIF() every time you add or remove a module. It would be nicer if modules could somehow register themselves in an array or list. One way to do that is to write functions that are called at program startup and/or library loading time. These are functions that go into a special dynamic linker section. How to get functions in there is not standard C, but with GCC at least you can use __attribute((constructor)) to mark a function as having to run before main() is started. Here is an example of how it could be used. First, ensure moduleIF contains its type identifier, and a pointer to the next moduleIF:

typedef struct moduleIF {     const int type; // or char *moduleName...     struct moduleIF *next;      struct moduleIF *(*init)(void);     void (*printCfg)(moduleIF_CTX *ctx);     ... } moduleIF; 

Then add a global variable that holds a pointer to the first module, and create a function to add new modules to that list:

moduleIF *modules = NULL;  void registerIF(moduleIF *if) {     if->next = modules;     modules = if; } 

Then in a module itself, like boatModule_Cnc.c, do:

static moduleIF boatIF {     .type = TYPE_CNC,     .init = init_Cnc,     .printCfg = printCfg_Cnc, };  static void registerBoatIF(void) __attribute__((constructor)); static void registerBoatIF(void) {     registerIF(&boatIF); } 

If you now link multiple modules into a single binary, then all of their constructor functions will be called before main() starts, so at that time modules will be a linked list containing all the registered module interface definitions. You can then change init_moduleIF() to:

moduleIF *init_moduleIF(int type) {     for (moduleIF *if = modules; if; if = if->next) {         if (if->type == type && if->init) {             return if->init();         }     }      return NULL; } 

About using weak and renamed symbols

I think this approach is less flexible than the one I outlined above. Also, if you know at compile time which .o files you are going to link together, then instead of using weak symbols, you can also compile boatModuleIF.c with -Dinit_moduleIF_CNC=NULL if you know the CNC module is not compiled in, or define something else and use #ifdefs inside init_moduleIF() to compile only those cases that are valid. I think that is just as pretty (or ugly, depending what you think of it) as using weak symbols, except that it relies less on linker tricks.

As for renaming the symbols, this is also unnecessary. printCfg() is static, and init_moduleIF_*() will just put a pointer to this local version of printCfg() in the moduleIF_t that is returned.

You do need to rename dfltBoatCfg, because otherwise only of the dfltBoatCfg instances survives the weak linking. But if you don't rename that symbol, it will compile and link without errors.

Another way to solve this issue is by not doing any symbol renaming tricks, and not having boatModule.c linked in multiple times. Instead, link it once in the final binary, and have it take a pointer argument that can be used to point to a custom boatCfg_t, like so:

moduleIF_t *init_moduleIF(const boatCfg_t *boatCfg) {     ...     if (cfg) {         CTX->size = boatCfg.size;         CTX->speed = boatCfg.speed;     }     ... } 

And for example in cnc.c, write:

#include "boatModuleDefs.h"  static const boatCfg_t boatCfg = {     .size = 10,     .speed= 10, };  moduleIF_t *init_moduleIF_CNC() {     return init_moduleIF(boatCfg); } 

It's just a few lines extra, but now I can just see what happens by looking at the source, instead of having to understand your build system as well. This approach is also more portable.

 
 
         
         

Relacionados problema

16  Rutas exportadoras en Node.js Express 4  ( Exporting routes in node js express 4 ) 
Estoy usando Express 4 para proporcionar rutas a archivos HTML / JADE, y también para proporcionar una API. Quiero separar las rutas del archivo del servido...

2  Patrón de código JavaScript  ( Javascript code pattern ) 
He estado trabajando en un proyecto pesado JavaScript. Hay ventas, compras, informes, etc. Lo que he hecho se creó un módulo separado para cada I.E. Un módulo...

9  Cargando y usando Scripts LUA  ( Loading and using lua scripts ) 
He estado experimentando con la integración de LUA en OBJETIVO-C. He tratado de hacer el mínimo para obtener LUA para calcular los valores y devolverlos. No q...

6  Juego de serpientes usando un lienzo  ( Snake game using a canvas ) 
Estoy tratando de alcanzar una buena comprensión de cómo construir una estructura de aplicación modular escalable. Recientemente he estado practicando con lie...

3  JavaScript Módulos Cargando con EVAL ()  ( Javascript modules loading with eval ) 
Recientemente pidí usarlo MyVar2 para una función de módulo . Ahora terminé haciendo una función muy extraña que hace lo que quiero. Me gusta la idea que l...

4  Fusionando con diferentes módulos  ( Merging with different modules ) 
Tenemos una combinación de acción para dos proyectos. En los proyectos tenemos diferentes módulos, como alimento, archivos, post, etc ... ["something"; "so...

4  Módulo para validar y sumar una cadena que no contiene números negativos  ( Module to validate and sum a string containing no negative numbers ) 
Para aprender el idioma de JavaScript, hice un ejercicio de dojo de Roy OsHerove. ¿Hay una mejor manera de organizar esto para que el único método exportado s...

5  Analizador de rss para nodo.js  ( Rss parser for node js ) 
Me gustaría que alguien revise este código y le diría si se puede hacer mejor, o si el código es elegante y lo suficientemente simple para la tarea en cuestió...

1  Biblioteca para imitar lienzo usando divs  ( Library to mimic canvas using divs ) 
Recientemente estuve desarrollando una biblioteca de lienzos y (imitando el lienzo con DIV). El requisito era desarrollar algo sin utilizar ninguna biblioteca...

0  Script de Analytics Ad-Hoc al módulo / Paquete  ( Ad hoc analytics script to module package ) 
Tengo un proceso de análisis de texto que complete para trabajar. Este proceso minas texto para diferentes cuentas de Twitter y encuentra patrones en los Twee...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos