Separating a program’s functions into
independent pieces,
each containing all the parts needed to execute a
single aspect
of the functionality
Modular programming enforce logical boundaries between components and improve maintainability
The same code can be used in many applications.
Teams can develop modules separately and do not require knowledge of all modules in the system.
Easily extend ANY application by just building on top of the modular architecture
API Versioning /API/v1
Validation & Security
Shared Utility
Mailing Services
Internationalization
ORM & Query Services
Logging & Debugging Service Integration
API Wrappers (s3,twilio,RabbitMQ,stripe,swagger, etc.)
box install jsondiff
Adam Cameron (TM)
(BUT FOR A MAJORITY...)
FYI some modules don't need to be injected
(eg. cbsecurity)
moduleSettings = {
qb = {
defaultGrammar = "MySQLGrammar@qb"
}
};
Step 1. Check to make sure you are searching for the right solution
DONT REINVENT THE WHEEL....
CHANCES ARE YOUR NOT THE FIRST TO HAVE THIS PROBLEM
LOOK FOR INSPIRATION FROM PROJECTS IN OTHER LANGUAGES
Maintenance Mode
SSL Support Interceptor
Deploy
Multi Domain SES
Reserved Routes
STRIPE API
PINGDOM API (UPTIME MONITOR)
SPOTIFY API
TWITTER API
RACKSPACE CLOUD API
CFSMARTYSTREETS (ADDRESS VERIFICATION/AUTOCOMPLETE)
TWILIO API (SMS/CALL SERVICES)
ALGOLIA API
300+ ADDITIONAL API WRAPPERS ON FORGEBOX.IO
COMMANDBOX BULLET TRAIN
QB (FLUENT QUERY BUILDER)
CFFLOW (WORKFLOW ENGINE)
QUICK (COLDBOX ORM)
INTEGRATED (INTEGRATION TESTING)
RULEBOX (RULE ENGINE)
COLDBOX TEMPLATING LANGUAGE
WEIGHTED ROUND ROBIN (RANDOMIZE WIDGETS)
INSPIRATION FROM JAVA, NODE, PHP, RUBY
CFZXING (BARCODE GENERATOR)
CB STREAMS (JAVA STREAMS)
ITEXTCFC (iTEXT PDF CREATOR)
SQL FORMATTER
CBMARKDOWN (MARKDOWN TO HTML)
RECURRENCE (RECURRING CAL EVENTS)
CBCODEHIGHLIGHT (PYGMENTS SYNTAX HIGHLIGHT)
JWT CFML (JWT TOKEN CREATION)
ALLOWING FOR SIMPLIFIED USAGE
OF EXISTING JAVA LIBRARIES
appMapping |
The appMapping setting of the current host application |
---|---|
binder | The WireBox configuration binder object |
cachebox | A reference to CacheBox |
controller | A reference to the application's ColdBox Controller |
log | A pre-configured LogBox Logger object for this specific class object |
logbox | A Reference to LogBox |
moduleMapping | The moduleMapping setting of the current module. This is the path needed in order to instantiate CFCs in the module. |
modulePath | The absolute path to the current loading module |
wirebox | A Reference to WireBox |
Every module can declare an array of helper templates that contain methods that will be added as global application helpers.
This is a great way to collaborate global functions to the running MVC application.
This is done via the this.applicationHelper
directive in your ModuleConfig.cfc
.
This is an array of relative paths in the module that ColdBox will load as mixins.
this.applicationHelper = [
"includes/helpers.cfm"
];
// Here is a sample of a helpers.cfm:
<cfscript>
function auth() {
return wirebox.getInstance( "AuthenticationService@cbauth" );
}
</cfscript>
<cfdump var=#( wirebox.getBinder().getMappings().keyArray() )#>
Helpful for debugging
create( class )
- Create a loaded Java classappendPath( dirPath, filter)
- Appends a directory path of .jar's,.classes to the current loaded class loader.getLoadedURLs()
- Get all the loaded URLscomponent accessors=true{
// DI
property name="javaLoader" inject="loader@cbjavaloader";
property name="settings" inject="box:modulesettings:bcrypt";
/**
* Constructor
*/
BCrypt function init(){
return this;
}
function onDIComplete(){
variables.bcrypt = variables.javaLoader.create( "org.mindrot.jbcrypt.BCrypt" );
}
}
function onLoad(){
// Register some tables in my database and activate some features
controller.getWireBox().getInstance('MyModuleService').activate();
log.info( 'Module #this.title# loaded correctly' );
}
function onUnLoad(){
// Cleanup some stuff and logit
controller.getWireBox().getInstance('MyModuleService').shutdown();
// Log we unloaded
log.info( 'My module unloaded successfully!' );
}
.github/workflows -
These are the GitHub actions to test and build the module via CI
FYI this template is set up for the normal ortus team workflow so if you decide to use the GitHub action workflow you will need to modify the settings
Automated Tests for your module in coldbox with multiple server versions
build -
This is the CommandBox task that builds the project. Only modify if needed. Most modules will never modify it. (Modify if needed
Does some initial scaffolding for your app to name it and set up its module name
box task run taskFile=build/setupTemplate
test-harness -
This is a ColdBox testing application,
where you will add your testing files, specs etc.
.cfformat.json -
A CFFormat using the Ortus Standards
{
"array.empty_padding": false,
"array.padding": true,
"array.multiline.min_length": 50,
"array.multiline.element_count": 2,
"array.multiline.leading_comma.padding": true,
"array.multiline.leading_comma": false,
"alignment.consecutive.assignments": true,
"alignment.consecutive.properties": true,
"alignment.consecutive.params": true,
"alignment.doc_comments" : true,
"brackets.padding": true,
"comment.asterisks": "align",
"binary_operators.padding": true,
"for_loop_semicolons.padding": true,
"function_call.empty_padding": false,
"function_call.padding": true,
"function_call.multiline.leading_comma.padding": true,
"function_call.casing.builtin": "cfdocs",
"function_call.casing.userdefined": "camel",
"function_call.multiline.element_count": 3,
"function_call.multiline.leading_comma": false,
"function_call.multiline.min_length": 50,
"function_declaration.padding": true,
"function_declaration.empty_padding": false,
"function_declaration.multiline.leading_comma": false,
"function_declaration.multiline.leading_comma.padding": true,
"function_declaration.multiline.element_count": 3,
"function_declaration.multiline.min_length": 50,
"function_declaration.group_to_block_spacing": "compact",
"function_anonymous.empty_padding": false,
"function_anonymous.group_to_block_spacing": "compact",
"function_anonymous.multiline.element_count": 3,
"function_anonymous.multiline.leading_comma": false,
"function_anonymous.multiline.leading_comma.padding": true,
"function_anonymous.multiline.min_length": 50,
"function_anonymous.padding": true,
"indent_size": 4,
"keywords.block_to_keyword_spacing": "spaced",
"keywords.group_to_block_spacing": "spaced",
"keywords.padding_inside_group": true,
"keywords.spacing_to_block": "spaced",
"keywords.spacing_to_group": true,
"keywords.empty_group_spacing": false,
"max_columns": 115,
"metadata.multiline.element_count": 3,
"metadata.multiline.min_length": 50,
"method_call.chain.multiline" : 3,
"newline":"\n",
"property.multiline.element_count": 3,
"property.multiline.min_length": 30,
"parentheses.padding": true,
"strings.quote": "double",
"strings.attributes.quote": "double",
"struct.separator": " : ",
"struct.padding": true,
"struct.empty_padding": false,
"struct.multiline.leading_comma": false,
"struct.multiline.leading_comma.padding": true,
"struct.multiline.element_count": 2,
"struct.multiline.min_length": 60,
"tab_indent": true
}
.cfformat.json - A CFFormat using the Ortus Standards
https://github.com/Ortus-Solutions/coding-standards/blob/master/coldfusion.md
.cflintrc - A CFLint configuration file according to Ortus Standards
{
"rule": [],
"includes": [
{ "code": "AVOID_USING_CFINCLUDE_TAG" },
{ "code": "AVOID_USING_CFABORT_TAG" },
{ "code": "AVOID_USING_CFEXECUTE_TAG" },
{ "code": "AVOID_USING_DEBUG_ATTR" },
{ "code": "AVOID_USING_ABORT" },
{ "code": "AVOID_USING_ISDATE" },
{ "code": "AVOID_USING_ISDEBUGMODE" },
{ "code": "AVOID_USING_CFINSERT_TAG" },
{ "code": "AVOID_USING_CFUPDATE_TAG" },
{ "code": "ARG_VAR_CONFLICT" },
{ "code": "ARG_HINT_MISSING" },
{ "code": "ARG_HINT_MISSING_SCRIPT" },
{ "code" : "ARGUMENT_INVALID_NAME" },
{ "code" : "ARGUMENT_ALLCAPS_NAME" },
{ "code" : "ARGUMENT_TOO_WORDY" },
{ "code" : "ARGUMENT_IS_TEMPORARY" },
{ "code": "CFQUERYPARAM_REQ" },
{ "code": "COMPARE_INSTEAD_OF_ASSIGN" },
{ "code": "COMPONENT_HINT_MISSING" },
{ "code" : "COMPONENT_INVALID_NAME" },
{ "code" : "COMPONENT_ALLCAPS_NAME" },
{ "code" : "COMPONENT_TOO_SHORT" },
{ "code" : "COMPONENT_TOO_LONG" },
{ "code" : "COMPONENT_TOO_WORDY" },
{ "code" : "COMPONENT_IS_TEMPORARY" },
{ "code" : "COMPONENT_HAS_PREFIX_OR_POSTFIX" },
{ "code": "COMPLEX_BOOLEAN_CHECK" },
{ "code": "EXCESSIVE_ARGUMENTS" },
{ "code": "EXCESSIVE_FUNCTIONS" },
{ "code": "EXPLICIT_BOOLEAN_CHECK" },
{ "code": "FUNCTION_TOO_COMPLEX" },
{ "code": "FUNCTION_HINT_MISSING" },
{ "code": "FILE_SHOULD_START_WITH_LOWERCASE" },
{ "code": "LOCAL_LITERAL_VALUE_USED_TOO_OFTEN" },
{ "code": "GLOBAL_LITERAL_VALUE_USED_TOO_OFTEN" },
{ "code": "MISSING_VAR" },
{ "code" : "METHOD_INVALID_NAME" },
{ "code" : "METHOD_ALLCAPS_NAME" },
{ "code" : "METHOD_IS_TEMPORARY" },
{ "code": "NESTED_CFOUTPUT" },
{ "code": "NEVER_USE_QUERY_IN_CFM" },
{ "code": "OUTPUT_ATTR" },
{ "code" : "QUERYPARAM_REQ" },
{ "code": "UNUSED_LOCAL_VARIABLE" },
{ "code": "UNUSED_METHOD_ARGUMENT" },
{ "code": "SQL_SELECT_STAR" },
{ "code": "SCOPE_ALLCAPS_NAME" },
{ "code": "VAR_ALLCAPS_NAME" },
{ "code": "VAR_INVALID_NAME" },
{ "code": "VAR_TOO_WORDY" }
],
"inheritParent": false,
"parameters": {
"TooManyFunctionsChecker.maximum" : 50
}
}
.editorconfig - Smooth consistency between editor (vscode coding settings)
# http://editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = false
indent_style = tab
indent_size = 4
tab_width = 4
[*.yml]
indent_style = space
indent_size = 2
[*.{md,markdown}]
trim_trailing_whitespace = false
insert_final_newline = false
.gitignore - Basic ignores. Modify as needed
# Artifacts and temp folders
.artifacts/**
.tmp/**
# Engine + Secrets
.env
.engine/**
# Dependencies
test-harness/coldbox/**
test-harness/docbox/**
test-harness/testbox/**
test-harness/logs/**
test-harness/modules/**
# modules
modules/**
# log files
logs/**
box.json - The box.json for YOUR module. Modify as needed
{
"name" : "JSON Diff",
"version" : "1.0.0",
"author" : "Scott Steinbeck,
"homepage" : "https://github.com/scottsteinbeck/cbjsondiff",
"documentation" : "https://github.com/scottsteinbeck/cbjsondiff",
"repository" : { "type" : "git", "url" : "https://github.com/scottsteinbeck/cbjsondiff" },
"bugs" : "https://github.com/scottsteinbeck/cbjsondiff",
"shortDescription" : "Description goes here",
"slug" : "cbjsondiff",
"type" : "modules",
"keywords":"",
"license" : [
{
"type" : "Apache2",
"url" : "http://www.apache.org/licenses/LICENSE-2.0.html"
}
],
"contributors" : [
],
"dependencies" :{
},
"devDependencies" :{
"commandbox-cfformat":"*",
"commandbox-docbox":"*",
"commandbox-dotenv":"*",
"commandbox-cfconfig":"*"
},
"ignore":[
"**/.*",
"test-harness",
"/server*.json"
],
"scripts":{
"setupTemplate": "task run taskFile=build/SetupTemplate.cfc",
"build:module":"task run taskFile=build/Build.cfc :projectName=`package show slug` :version=`package show version`",
"build:docs":"task run taskFile=build/Build.cfc target=docs :projectName=`package show slug` :version=`package show version`",
"release":"recipe build/release.boxr",
"format":"cfformat run helpers,models,test-harness/tests/,ModuleConfig.cfc --overwrite",
"format:watch":"cfformat watch helpers,models,test-harness/tests/,ModuleConfig.cfc ./.cfformat.json",
"format:check":"cfformat check helpers,models,test-harness/tests/,ModuleConfig.cfc",
"cfpm":"echo '\".engine/adobe2021/WEB-INF/cfusion/bin/cfpm.sh\"' | run",
"cfpm:install":"echo '\".engine/adobe2021/WEB-INF/cfusion/bin/cfpm.sh\" install ${1}' | run",
"install:2021":"run-script cfpm:install zip,debugger"
},
"testbox":{
"runner":"http://localhost:60299/tests/runner.cfm"
}
}
changelog.md - A nice changelog tracking file
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
----
## [1.0.0] => 2021-JAN-01
* First iteration of this module
ModuleConfig.cfc - Your module's configuration. Modify as needed
/**
* Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp
* www.ortussolutions.com
* ---
*/
component {
// Module Properties
this.title = "JSON Diff";
this.author = "Ortus Solutions";
this.webURL = "https://www.ortussolutions.com";
this.description = "Take 2 coldfusion structs or arrays and return the differences between them";
this.version = "@build.version@+@build.number@";
// Model Namespace
this.modelNamespace = "cbjsondiff";
// CF Mapping
this.cfmapping = "cbjsondiff";
// Dependencies
this.dependencies = [];
/**
* Configure Module
*/
function configure(){
settings = {
ignoreKeys = []
};
}
/**
* Fired when the module is registered and activated.
*/
function onLoad(){
}
/**
* Fired when the module is unregistered and unloaded
*/
function onUnload(){
}
}
readme.md - Your module's readme. Modify as needed
readme.md - Your module's readme. Modify as needed
server-xx@x.json - A set of json files to configure the major engines your modules supports.
These can be used for testing manually or will automatically be run by Github Actions
cd test-harness
box install
start lucee@5
browse to the webpage
API Docs - build/Build.cfc
The build task will take care of building API Docs using DocBox for you but **ONLY** for the `models` folder in your module.
if you need more items documented you can modify the build.cfc file