Coding Manual and Guidelines for Mach II Framework Coding - Mach-II/Mach-II-Framework GitHub Wiki

By Peter J. Farrell (peter@…)

Table of Contents

  1. Introduction
  2. Copyright
  3. General
  4. Commenting
  5. Variables
  6. Code Formatting
  7. Coding Preferences
  8. Making Commits

Introduction

This manual and guidelines document was developed to continue the effort to maintain the consistency of code formatting, style and syntax that the framework uses. Team Mach-II believes that following these guidelines will help Mach-II Framework developers to write more maintainable code and continue the consistent coding style set forth by previous versions.

Copyright

  • All text and source code files must have a file header comment section that includes our license and copyright notices. All Mach-II code is released under the GPL3 License with Classpath Exception. All files must have the license notice in the file header comments for it to be included under the Apache 2.0 license. If you are a creator of a new file which will be committed to our repository for the first time, you should fill out the appropriate contributor name and email address; otherwise leave the attribute section as it was defined by the original contributor. We use this information for tracking the original contributor for legal reasons (i.e. copyright disputes, patent grants, etc.).

Below is a sample:

    <!---
        Mach-II - A framework for object oriented MVC web applications in CFML
        Copyright (C) 2003-2010 GreatBizTools, LLC

        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>.

        Linking this library statically or dynamically with other modules is
        making a combined work based on this library.  Thus, the terms and
        conditions of the GNU General Public License cover the whole
        combination.

        As a special exception, the copyright holders of this library give you
        permission to link this library with independent modules to produce an
        executable, regardless of the license terms of these independent
        modules, and to copy and distribute the resulting executable under
        terms of your choice, provided that you also meet, for each linked
        independent module, the terms and conditions of the license of that
        module.  An independent module is a module which is not derived from
        or based on this library.  If you modify this library, you may extend
        this exception to your version of the library, but you are not
        obligated to do so.  If you do not wish to do so, delete this
        exception statement from your version.

    Author: Your Name ([email protected])
    $Id: $

    Created version: 1.8.1
    Updated version: 1.8.1
    --->
  • All contributed code, file, graphics, etc. become the property of the Mach-II project under the terms of contributors license. See how to become a contributor for more information.

General

  • All code must be able to run on Adobe ColdFusion 7+ and Open BlueDragon . Do not use newer functions or tags that are not available on those CFML engines (with the exception of the threading adapter that abstracts the different threading implementations).

  • We use close all tags with trailing slashes / (XML style) with the exception of <cfelse>.

        <cfset variables.foo = "bar" />
  • Refrain from using <cfscript> as it has various implementations across different CFML engines.

  • All method names should be descriptive and use a verb. Usually, the verb will began the method name. All method names should be typed in lowerCamelCase not CamelCase.

  • All method calls should follow the lowerCamelCase typing, except for built-in functions (BIFs - functions built into the CFML engine) which should follow the CamelCase typing. Examples:

        <cfset var propertyManager = getAppManager().getPropertyManager() />
        <cfif StructKeyExists(arguments, "someElement")>
            <cfset something = arguments.someElement />
        </cfif>

Commenting

  • All methods should have a hint except for getters/setters. If the setter / getter does something like data validation, it is a good idea to document this additional behavior in the hint of the method.
  • All code comments should explain the intent of the code and should not describe what the code does. Comments like loop over this are less helpful than search this to see if we need to do that.

Variables

  • All variables must be prefixed by the correct scope.

  • Use variable names that describe the purpose of the variable. Do not use nonsensical variable names like x or tmp or abbreviate parts of the variable name.

  • Define all variables that local to a single invocation of a method by var'ing each variable at the top of the method. We do not use a var'ed local scope (var local = StructNew()).

  • Access external scopes (e.g. request, application, session, etc.) by passing them into CFCs versus referencing them directly within the CFC.

  • All variables names should be lowerCamelCased not CamelCased or ALLCAPS.

    <cfset variables.somethingCool = 1 />
    <cfset var someElement = arguments.thisStruct.someElement />

Code Formatting

  • All CFCs should follow a similar format with the following sections in the order of properties, initialization / configuration, public functions, public functions - utils, protected functions and accessors (see example below).
  • All var'ed variables should have one line of space between the top of <cffunction> tag and the first var'ed variable and one line of space between the last var'ed variable and the first line of logic.
  • All function attributes should be in the order of name, access, returntype, output and hint.
  • Hint attributes are required for all methods except for getters/setters (although we encourage hints for getters/setters that perform logic other than getting or setting data such as validation or data formating). The hint attribute should be the first line below the function tag with one tab in.
  • Avoid multiple <cfreturn>s in a function unless the code requires short-circuiting logic. Multiple returns can lead to confusing to read code.
    <!---
        Mach-II - A framework for object oriented MVC web applications in CFML
        Copyright (C) 2003-2010 GreatBizTools, LLC

        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>.

        Linking this library statically or dynamically with other modules is
        making a combined work based on this library.  Thus, the terms and
        conditions of the GNU General Public License cover the whole
        combination.

        As a special exception, the copyright holders of this library give you
        permission to link this library with independent modules to produce an
        executable, regardless of the license terms of these independent
        modules, and to copy and distribute the resulting executable under
        terms of your choice, provided that you also meet, for each linked
        independent module, the terms and conditions of the license of that
        module.  An independent module is a module which is not derived from
        or based on this library.  If you modify this library, you may extend
        this exception to your version of the library, but you are not
        obligated to do so.  If you do not wish to do so, delete this
        exception statement from your version.

    Author: Your Name ([email protected])
    $Id: $

    Created version: 1.8.1
    Updated version: 1.8.1

    Notes:
    --->
    <cfcomponent
        displayname="AppManager"
        output="false"
        hint="The main framework manager.">

        <!---
        PROPERTIES
        --->
        <cfset variables.appLoader = "" />
        <cfset variables.parentAppManager = "" />


        <!---
        INITIALIZATION / CONFIGURATION
        --->
        <cffunction name="init" access="public" returntype="AppManager" output="false"
            hint="Used by the framework for initialization. Do not override.">
            <cfreturn this />
        </cffunction>

        <cffunction name="configure" access="public" returntype="void"
            hint="Calls configure() on each of the manager instances.">

            <!--- In order in which the managers are called is important
                DO NOT CHANGE ORDER OF METHOD CALLS --->
            <cfset getPropertyManager().configure() />
            <cfset getCacheManager().configure() />
            <cfset getRequestManager().configure() />
            <cfset getPluginManager().configure() />
            <cfset getListenerManager().configure() />
            <cfset getMessageManager().configure() />
            <cfset getFilterManager().configure() />
            <cfset getSubroutineManager().configure() />
            <cfset getEventManager().configure() />
            <cfset getViewManager().configure() />

            <!--- Module Manager is a singleton only call if this is the parent AppManager --->
            <cfif NOT IsObject(getParent())>
                <cfset getModuleManager().configure() />
            </cfif>

            <!--- Flip loading to false --->
            <cfset setLoading(false) />
        </cffunction>

        <!---
        PUBLIC FUNCTIONS
        --->
        <cffunction name="getRequestHandler" access="public" returntype="MachII.framework.RequestHandler" output="false"
            hint="Returns a new or cached instance of a RequestHandler.">
            <cfargument name="createNew" type="boolean" required="false" default="false"
                hint="Pass true to return a new instance of a RequestHandler." />
            <cfreturn getRequestManager().getRequestHandler(arguments.createNew) />
        </cffunction>

        <!---
        PUBLIC FUNCTIONS - UTILS
        --->
        <cffunction name="inModule" access="public" returntype="boolean" output="false"
            hint="Returns a boolean on whether or not this AppManager is a module AppManager.">
            <cfreturn IsObject(getParent()) />
        </cffunction>

        <!---
        PROTECTED FUNCTIONS
        --->

        <!---
        ACCESSORS
        --->
        <cffunction name="setEnvironment" access="public" returntype="void" output="false"
            hint="Sets the environment.">
            <cfargument name="environment" type="string" required="true" />
            <cfif NOT IsObject(getParent())>
                <cfset variables.environment = arguments.environment />
            <cfelse>
                <cfthrow type="MachII.framework.CannotSetEnvironment"
                    message="Cannot set environment from module. Modules can only inherit environment from parent application." />
            </cfif>
        </cffunction>
        <cffunction name="getEnvironment" access="public" returntype="string" output="false"
            hint="Gets the environment. If module, gets value from parent since environment is a singleton.">
            <cfif IsObject(getParent())>
                <cfreturn getParent().getEnvironment() />
            <cfelse>
                <cfreturn variables.environment />
            </cfif>
        </cffunction>

        <cffunction name="setModuleName" access="public" returntype="void" output="false"
            hint="Sets the module name for this instance of the AppManager.">
            <cfargument name="moduleName" type="string" required="true" />
            <cfset variables.moduleName = arguments.moduleName />
        </cffunction>
        <cffunction name="getModuleName" access="public" returntype="string" output="false"
            hint="Gets the module name for this instance of the AppManager.">
            <cfreturn variables.moduleName />
        </cffunction>

    </cfcomponent>

Coding Preferences

Most of the coding preferences have been setup to keep the code base similar as it matures or have been setup to allow for maximum cross CFML engine compatibility for our target engines and versions.

Conditions

  • Favor using short circuit conditions when multiple conditionals are in an if or elseif statement. This allows the condition to fast-fail which ultimately improve performance as all CFML engine will skip over the code block upon discovering the first condition that fails and will not evaluate any other conditions.
  • When evaluating a boolean, there is no need to test the condition using myBoolean EQ false or myBoolean EQ true. All conditionals use boolean logic:
    • Use <cfif myBoolean> when checking if true
    • Use <cfif NOT myBoolean when checking if false

Loops

Arrays

  • Loop index variable names should always be used in the following order:

    • i
    • j
    • k
    • l
    • If you need more than four index variables names, you might consider refactoring your code.
  • Not all CFML engines version we support allow for <cfloop array="" ... > so favor using the "old-fashioned" <cfloop from="1" to="#ArrayLen(myArr)#" index="i"> notation.

Structs

  • Loop item variable names should always be something related to the struct you are iterating over. Favor descriptive names:
    • urlParameterKey
    • myKey
    • key
    • Variable names like i or k can easily be confused with array index names so favor not to use this names.

Method Calls

  • Favor using StructKeyExists() over IsDefined() when possible
  • Favor using direct struct declaration (e.g. myStruct.key = "something" or myStruct[keyName] = "something") over StructInsert(). Use StructInsert() only when you want to throw an exception when a key is already defined. This behavior is better than having to test for a key name first with StructKeyExists().

Making Commits

  • Do not commit code that will break the build. Instead make a person branch in the branches folder of the version you are working in.
  • All commits must have a full length and descriptive commit note. Our repository will reject any commits that do not have any commit notes.
  • If you are committing code on behalf of another person that is not an official contributor, you must that contribution Committed on behalf of Full Name ([email protected])
  • If you commit is in reference to a ticket, always note the ticket in the commit note. Trac post-commit hook uses the syntax of command[t:123] where 123 is a ticket number and command is action to be taken. Valid commands are fix, fixes , fixed, close, closes and closed which will automatically mark the referenced ticket as closed. If you wish to reference a ticket without closing it which will leave it in its current state, use addresses, re, references, refs and see. Examples fixes[t:47] or addresses[t:51] or see[t:42].
  • All .txt, .cfc and .cfm file should have the id SVN keyword property attached to them.

Back to FAQs

⚠️ **GitHub.com Fallback** ⚠️