[!] - This style guide is not yet comprehensive, as it was first published for internal reference. Where ambiguities exist, ask members of Confoederatio for help, or use your best judgement.
A standard scheme of HTML/CSS/JS/Node programming is required to maintain cross-project code compatibility. This often includes sharing software engines and frameworks, which are currently being worked on. Complete documentation for Universal Framework (UF), used both for frontend/backend building in Node/Electron will be provided post-Naissance.
Confoederatio projects take on a modular imperative paradigm, where software are divided into discrete Mechanics, which have both a frontend (ui) and backend (framework) element. Inside this piece of documentation, * always means optional. The rationale for clauses of code should always be well-explained.
Your code should always be ES5-compatible. Avoid syntactic sugar and prioritise readability.
Single-line comment format: /* – <Comment here> – */
Single-line comment format: <!-- <Comment here> -->
Line comments (//) should never have spaces between them and their comments.
//<Comment here>.
/*
<Comment here>
*/
Note. In complex boolean statements, it is recommended to use parenthetical/round bracket grouping to increase readability. These should be indented and placed on different lines.
When handling error statements that are the result of end-user input, do not throw an error to the console. Instead, these should simply result in the operation not being invoked. Similarly, for compatibility reasons, when checking whether subvariables exist in a given object, it is recommended practice to chain indentation together as follows:
if (global.undo_redo_trees)
if (global.undo_redo_trees[timeline_id]) {
//Multi-line code here
}
This practice is recommended for JS version compatibility reasons instead of using ?. operators.
Singular if-statements should not use curly braces if the line of code to be executed after the if statement is only one line long. Rather, they should utilise a newline with an indent prior to an expression/function call. Two or more? Use a curly brace.
If-else statements that are not ternaries should always use curly braces. Otherwise, why did people invent ternaries?
Switch cases should not be used due to their conditional rigidity and slower performance. Else-if chains are always preferred to switch-cases. What if a change comes up and you need complex conditionals now? Exactly.
In cases where ternaries are possible, they should always be used instead of if/else statements for brevity (in variable assignments; if/else function calls). Within the ‘Convert from parameters’ section, they should always be inline. Otherwise, outside of these function sections (e.g. ‘Declare local instance variables’), they should be placed beneath.
Ternaries should never be nested or chained together.
Function names should be camelCased, with functions in a file always being arranged in alphabetical order. Names should be as surgically descriptive of what the function does as possible. Parameters should always be specified in the following format:
arg<#>_<parameter_name>, …, arg<#>_options
(if complex object parameters would help increase readability, recommended for functions with more than one optional parameter and/or more than four arguments).
Some programmers do noit understand the need for arg<#>. The rationale is that it allows for speedy refactoring using Ctrl + Find in addition to JSDoc support - external parameter names are standardised, whilst internal parameters are localised. # is 0-indexed.
Functions should almost always be global, unless the module is critical to startup/load order.
Functions additionally always follow the same section order:
//Convert from parameters
arg<#>
format should always be stripped at this stage. Only variables directly referencing function parameters should be placed within this section._options
parameter exists in this function, it should always be defined as a ternary like so: var options = (arg4_options) ? arg4_options: {}
. The options parameter is always an object.//Initialise options
//Declare local instance variables
//Guard clause <Comment here>
//Return statement
Each function section is to be separated from each other by a double-line break. In general, double-line breaks are encouraged throughout code to separate functional clauses, especially when they encourage readability. Do not use excessive double-line clauses. If functions have parameters or a return statement, there should always be a multiline comment directly above them documenting it using JSDoc.
Variable Types/Return Values should be formatted in a specific manner when documented outside of JSDoc. As a specific example to how function documentation should be:
/*
createArray() - Creates an array from the following options.
arg0_options: (Object)
domain: (Array<Number, Number>) - Creates an integer array between min, max.
linear_sequence: (Array<Number, Number, Number>) - Generates a linear sequence from linear_sequence[0] to linear_sequence[1] in steps of linear_sequence[2].
sequence: (Array<String>, Number) - Generates a sequenced array according to a mathematical equation.
sequence[0] - Mathematical equation as a string literal. The current iteration when generating the sequence is referred to as 'n'.
sequence[1] - The total number of iterations to repeat the sequence for.
repeat: (Array<Array<...>, Number>) - Repeats an array x times.
repeat_each: (Array<Array<...>, Number>) - Repeats each element of an array x times.
Returns: (Array)
*/
createArray() {
//Code here.
}
Additionally, if a variable can be multiple datatypes, it should use a / to conjoin them. Sub-datatypes should be indicated using a comma after its parent datatype.
Iterator letter order should always be the same: (i, x, y, z, a, b, c, …) following mathematical sum notation for graphs where this is a typical letter pattern. Do not use any other letter sequence. Programmers may not be used to this notation. This originated from operations for iterating over a series of graphs (i = iterator, x = X axis, y = Y axis, z = Z axis, rollover to a, b, c, etc), particularly in 3D environments, though it is no longer strictly for that purpose.
Additionally, for loops should not use curly braces if only one line of code is being executed by them.
setInterval functions should have the following format:
setInterval(function(){
//Code
}, <iteration_delay>, <local_variable1>*, ...);
These may be assigned to a local variable if necessary.
setTimeout is used as a wait command. It follows the same formatting as that reserved for setInterval. (async/await is generally not compatible with ES5, so don't use it, unless your code will never touch Java).
You haven't solved the halting problem? Then don't use a while loop. It fails silently - then freezes your piece of software. For loop iteration is almost always controlled by a single line in code production. If you are changing the boundary within your for loop, there's a solution: simply iterate in reverse.
On the other hand, while loops are controlled by numerous scattered lines in code production.
When typing out equations, no operations should have spaces apart from + and -. So correct equation formatting would look like this: 5*9 + 4
. Not 5*9+4
or 5 * 9 + 4
.
Maths is centred around the idea of order of operations (BODMAS) and terms in equations. By tradition, closer operations are performed first. This is why Latex will always format say, ‘5 / 3’ as 5/3, without a space. Similarly, when people write out ordinal fractions, they will write ‘5/3rds’ and never ‘5 / 3rds' with a space. Natural language and mathematics agree.
SEPARATE YOUR TERMS. Unreadable and uncaught equations account for ~19% of all scientific retractions (Nature), and data management errors as a total for 63%. This is not a minor nitpick.
In fact, this type of technical equation formatting prioritising the visual grouping of terms and juxtaposition are as old as Apollo 11 technical comments:
Comanche055/CM_ENTRY_DIGITAL_AUTOPILOT.agc:
# Page 293
# THE EQUATIONS ARE
# - - - -
# RT = RTINIT + RTNORM (COS(WT) - 1) + RTEAST SIN(WT)
# WHERE WT = WIE DTEAROT
# RTINIT = INITIAL TARGET VECTOR
# - - -
# RTEAST = UNITW*RTINIT
# - - -
# RTNORM = RTEAST*UNITW
# Page 1082
GETLCX CA POS1/2 # FORM RCOM/360
DOUBLE
AD ROLLC
XCH LCX/360 # IGNORE POSSIBLE OVFL.
CA SR # FORM -R/360
AD NEG1/2
AD NEG1/2 # IGNORE OVFL
XCH LCX/360 # -R/360
ADS LCX/360 # LCX/360 = RCOM/360 - R/360 RANGE (-1,1)
Variables should always be defined inside of a function, never outside of one. Additionally, variables should always be declared in alphabetical order, with double line breaks used to split groups of variable declarations (similar to paragraphs in English grammar). The only exception to declaring variables in alphabetical order is in the //Convert from parameters
section, where variables are declared in parameter order.
Variable names should always be snake_cased, and as such are surgically descriptive of the variable's contents as possible.