¿Cómo se organizan sus pequeños cofres reutilizables?

Estoy reorganizando mis estructuras de directorio de ColdFusion y tengo curiosidad sobre cómo los desarrolladores experimentados de CF están organizando bibliotecas de funciones más pequeñas.

No tengo tanta curiosidad sobre los componentes elaborados (objetos) como sobre las docenas de pequeñas funciones de utilidad que todos construimos a lo largo del tiempo.

  • ¿Utiliza un solo archivo grande con funciones y cfinclude?
  • ¿Utiliza un único archivo grande como un componente cf y llama a creatobject / cfinvoke?
  • ¿Pone cada función de utilidad en su propia cfc y llama a createobject / cfinvoke?
  • ¿Usas la syntax cfimport taglib?
  • ¿Utiliza CustomTags o cfmodule?
  • ¿Tienes una mejor manera?

Como no me gusta la syntax detallada, he estado simplemente incluyendo un lib.cfm que tiene un montón de funciones comunes en él. Puedo refactorizarlos a cfcs agrupados en los que puedo crearobjeto solo para tener un mejor aislamiento en los ámbitos de variable.

¿Hay una mejor manera de hacer esto?

Esta es una reimpresión de una publicación de blog que hice el 13 de junio de 2007. ¡He estado usando este método durante bastante tiempo y funciona muy bien! YMMV.

¿A quién no le gustan las funciones definidas por el usuario (UDF)? Si ha realizado alguna progtwigción, es probable que la haya usado extensamente. El mayor problema que las personas tienen con ellos es cómo incluirlos y organizarlos en su aplicación.

Lo que descubrí que la mayoría de las personas hace es crear un Utils.cfc o UDFs.cfc y cortar y pegar sus UDF que quieren usar en el componente como se demuestra a continuación:

          

Una vez que tenga todas las UDF que su aplicación usará pegadas en su componente, deberá hacer que las UDF estén disponibles para su aplicación. Casi todos los que he visto lo cargan por el componente en el scope de la aplicación. La siguiente línea se coloca en onApplicationStart() si está utilizando Application.cfc o si simplemente lo agrega a Application.cfm si está utilizando eso:

  

Cualquiera que esté usando, Application.cfc o Application.cfm, los resultados son los mismos; todas sus UDF están disponibles para su aplicación y puede usarlas libremente en todas partes. La única diferencia es qué nombre de variable usa. Uso las funciones de aplicación, algunas usan application.utils o application.udfs; no importa, una vez más, los resultados son los mismos.

Sin embargo, hay un problema que tengo con este enfoque, es engorroso y el componente UDF será enorme. El problema de tener un archivo de componentes tan grande es la edición, se convierte en una pesadilla ya que desplazarse por miles de líneas de código no es muy divertido y también me he dado cuenta de que CFEclipse se atasca en archivos de gran tamaño. El colapso del código seguro proporciona cierto alivio, pero tiene que haber una mejor manera.

Lo que quería era tener solo un archivo para cada UDF que estaba usando y una forma para que mi aplicación los cargara automáticamente. La razón detrás de esto era que si necesitaba editar myUDF1 , podía simplemente abrir el archivo myUDF1.cfm y editar lo que necesitaba. También quería poder tomar UDF de CFLib.org y simplemente colocarlos en mi aplicación sin tener que editar nada. Si alguna vez necesitaba eliminar una UDF de mi aplicación, sería tan fácil como borrar el archivo UDF y reiniciar mi aplicación.

Para lograr lo que quería, modifiqué mi UDFs.cfc a 11 líneas de código:

             

Entonces, ¿qué está pasando exactamente?

En pocas palabras, esto es lo que está pasando: tengo un directorio llamado udfs en el mismo directorio que tengo mi UDFs.cfc. Este es el directorio donde pongo todos mis archivos UDF CFM. Lo que UDFs.cfc hace es escanear este directorio cuando se llama y automáticamente incluye cada archivo CFM que encuentra. Por lo tanto, carga automáticamente todas las UDF en la carpeta UDFs (comúnmente llamada “mixin”).

¡Entonces mi objective es alcanzado! Tengo cada UDF en su propio archivo, así que no tengo que desplazarme a través de un enorme archivo de componente para encontrarla. Ahora puedo abrirlo y editarlo fácilmente. Con solo mirar el directorio, sé qué UDF está usando mi aplicación. Puedo agregar automáticamente un UDF desde CFLib.org simplemente guardando el texto del navegador en un archivo en el directorio. Además, si ya no necesito usar el UDF en mi aplicación, simplemente elimino el archivo del directorio y se elimina de mi aplicación durante el próximo reinicio. Todo esto se hace sin tener que tocar el archivo principal UDFs.cfc.

A continuación se muestra un ejemplo de cómo se ve uno de los archivos UDF CFM. El archivo se llama fullLeft.cfm y reside en el directorio UDFs.

                 

Creo que esto depende de tu estilo de progtwigción, ve con el estilo que te resulte más cómodo. Encuentro que la forma más fácil es en application.cfm, establecer una variable en el scope de la aplicación para un componente cfcon todas mis funciones de utilidad:

    

Ahora puede llamar a métodos en application.utitlies desde cualquier lugar. Tenga en cuenta que si realiza cambios en su componente cf, debe actualizar su variable de aplicación con una nueva instancia de Utilidades.

si está utilizando Application.cfc (si no es así, le sugiero que migre desde Application.cfm, es muy fácil de hacer), puede comstackr un baseComponent.cfc con todos sus métodos UDF y heredar Application.cfc de baseComponent. luego, en el método onRequestStart establece una variable llamada request.app = this;

para la solicitud de entiure, puede usar request.app.methodname () para acceder a la UDF. su manera muy agradable y simple de manejar UDF

Además, si lo desea, puede hacer que todos sus cfcs hereden del mismo baseComponent para que todos sus cfcs tengan esas funciones de utilidades como métodos nativos. hace que la prueba unitaria de los cfcs sea muy fácil porque los cfcs no necesitan responder en una referencia pasada (inyectada) al componente UDf, ¡son descendientes de este!

Un desafío con este enfoque es que el atributo extends de un cfc no puede ser una expresión … así que dependiendo de cómo empaque sus componentes, esto puede ser difícil de implementar. la forma más fácil de manejarlo es con un mapeo de coldfusion.

hth Jon

Usamos archivos .cfm para bibliotecas de funciones y llamamos al archivo apropiado con cfinclude. Algunos de los archivos .cfm se han descargado de cflib.org y otros los hemos escrito nosotros. Los archivos están en un directorio llamado UDF que es un subdirectorio de otro directorio que está asignado al carácter de barra diagonal. La statement cfinclude es simplemente:

  

Este enfoque hace que las funciones estén disponibles para todas las aplicaciones en el servidor.

También preferimos el enfoque de varias bibliotecas pequeñas. Cada biblioteca es específica del tema (matemática, cadena, matriz de lista, etc.)

Opción: ¿Utiliza un único archivo grande con funciones y cfinclude?

R: Lo he hecho pero lo hago cada vez menos. Me gusta aprovechar la herencia y cfcexplorer

Opción: ¿Utiliza un único archivo grande como un componente cf y llama a creatobject / cfinvoke?

A: Sí, a menudo hago esto

Opción: ¿Pone cada función de utilidad en su propia cfc y llama a createobject / cfinvoke?

R: Podría hacer esto si espero agregar funciones adicionales más tarde

Opción: ¿Utiliza la syntax de cflport taglib?

A: yo hago cosas así de esa manera

Opción: ¿Utiliza los CustomTags?

R: No en mucho tiempo. cfc’s son mejores en esto

Opción: o cfmodule?

R: No en mucho tiempo. cfc’s son mejores en esto. el ámbito de llamador. * puede dificultar la depuración

Me doy cuenta de que esta es una vieja pregunta, pero utilizo un enfoque un poco diferente para estos temas.

Función de Utilidad / Enfoque Singleton con ‘Inyección’

Creo un cfc ‘core’ o ‘utility’. En él empaco todas mis funciones de tipo de utilidad que son:

  • Se usa frecuentemente todo el tiempo en todas partes (como un viewRecord() dao genérico y una función core checkSecurity() , et al.)
  • Son funciones base que deberían ser centrales en CF (como lpad() , capitalize() , et al)
  • Son envoltorios de algunas tags que me permiten usar cfscript ubicua (como exit() que envuelve )

En onApplicationStart() , creo una instancia de este objeto y lo asigno al ámbito de la Application , creando así un singleton estático de ordenaciones.

Entonces, en lugar de extender o volver a incluir esto en casi todos mis cfc, lo que me permite usar la extensión para un tipo de herencia más tradicional, entonces inyecté estos métodos en el constructor (el init) de todos mis cfc’s build. Lo hago llamando a un método en el objeto de utilidad en sí, de modo que:

 public/remote any function init() { structAppend( Variables, Application.MyApp.Objects.oCore.injectCoreMethods() ); return this; // Return instance of this object } 

El método injectCoreMethods() devuelve selectivamente una estructura de las funciones de utilidad que quiero extender virtualmente a todos mis objetos. No necesariamente inyecta todos los métodos de utilidad. Los menos utilizados, incluido injectCoreMethods() sí mismo, aún deberían abordarse a través del puntero de aplicación singleton completo de modo que Application.MyApp.Objects.oCore.infrequentMethod() .

Al inyectar en el ámbito de Variables , que está protegido, estos métodos serán efectivamente métodos privados. Por lo tanto, los volcados de los objetos no mostrarán estas funciones de utilidad, pero son perfectamente accesibles dentro del cfc por todos sus métodos directos.

Organización de archivos:

En general, he caído en el patrón de tener un cfc por carpeta. En cada carpeta, tengo un archivo cfc para el componente y el init. Todos los demás métodos los divido en archivos cfm y los incluyo en ese cfc. Hago esto para:

  1. Evite los archivos cfc gigantes de más de 1000 líneas que pueden ralentizar mi IDE (yo uso aptana / cfeclipse)
  2. Permita que los cambios se graben / rastreen de forma más discreta en un archivo por archivo y, por lo tanto, grabados en mi SCM / software de control de versiones.
  3. Permita que más de una persona trabaje en un objeto dado sin que el código se golpee entre sí.

Entonces, un objeto dao que contiene 4 métodos crud sería algo como esto:

 /code/dao/dao.cfc /code/dao/_removeRecord.cfm /code/dao/_addRecord.cfm /code/dao/_viewRecord.cfm /code/dao/_editRecord.cfm 

El cfc solo contiene los comentarios init() y de auto-documentación y en el área de pseudo-constructor incluyo los cuatro métodos. Esto también me permite tomar cualquier cfc por su carpeta y moverlo a alguna parte.

Lo mismo para la utilidad cfc. Se encuentra en su propia carpeta y tiene alrededor de 30 funciones extrañas entre 10 o más archivos cfm (algunas funciones simples las dejo en el mismo archivo como _string.cfm que en realidad contiene lpad() , rpad() , etc. todas relacionadas con cadenas. captar la idea.)

Módulos y tags personalizadas

Los evito a toda costa porque deben registrarse y obstaculizar las mudanzas / implementaciones fáciles. No me gustan las cosas que no se configuran solo al arrastrar y soltar de un entorno a otro. CF5: tenías que hacer las cosas de esta manera mucho más. Pero desde CF6 y la capacidad de usar objetos en un patrón de OOP real, ¿por qué querrías? Hay muy pocos casos que desee / necesite si los tiene.

Otro

Solía ​​poner funciones ‘core’ en el base.cfc que se extiende automáticamente a todos los cfc generados por CF (búscalo, agrega una función y ¡listo! Algo así como agregar cosas al prototipo en js). Realmente me gustaba mucho, pero era un problema para la implementación / mantenimiento.

Hasta cierto punto, tomo un enfoque de Fábrica. A menudo pongo una cantidad considerable de cfc estáticos en la aplicación como el núcleo. Un controlador lee una tabla de control genérica y configura todos los objetos en un bucle junto con un montón de otras cosas en el inicio de la aplicación como variables de la aplicación. Pero algunos objetos se instancian según sea necesario, obviamente los objetos pesados ​​y los objetos que contienen datos manipulables [semi] persistentes caen en esa categoría

De alguna manera, he estado haciendo esto desde CF7. Con CF9 + se está volviendo bastante fácil, maduro y resbaladizo.