Language-agnostic coding standard.
Efficiently develop code and applications with the following qualities :
- Robust : runs without crash and protects the data from being lost or corrupted.
- Secure : protects the data from being stolen or hacked.
- Ergonomic : does exactly what the user needs and can be used in a productive and intuitive manner.
- Efficient : minimizes processing times to maximize the user productivity.
- Maintainable : is easy to fix and enhance by any programmer in the team.
- Extensible : is easy to extend with new features by reusing existing components.
- Consistent : looks like it has been designed and implemented by a single developer.
This coding standard targets self-documenting code, and therefore favors readability over compactness by :
- forbidding the use of cryptic acronyms, abbreviations, prefixes and suffixes;
- using only letter cases to distinguish classes, class members and local variables;
- including the class name in attributes and variable names.
-
Design before you code by quickly writing :
- a short text or UI flow showing how to use the application, to optimize the user interface before implementing it;
- a short text or database design showing how the information will be stored, to optimize the data architecture before implementing it;
- a short text or component design showing how the application will be structured, to optimize the component architecture before implementing it;
- a short text or test code showing how to use the application components, to optimize the component interface before implementing it.
-
Develop programs gradually, starting with the data components, then implementing one external feature at a time.
-
Don't overgineer your code, choose simple modular designs which can easily be extended.
-
Don't repeat yourself, create reusable components that you can use several times across one or several projects.
-
Develop the application and its components with simple efficient maintainable code that :
- is stable and robust;
- is easy to understand just by itself, without comments or surrounding context;
- can be easily extended and debugged by any programmer in the team;
- fully complies with the coding standard, to the point it's impossible to guess who has worked on it.
-
Instead of adding comments to explain the code intent, refactor the code itself to make this intent obvious by :
- using clear consistent unambiguous names for all classes, attributes, functions, parameters and variables;
- using local variables to store intermediate results;
- splitting long functions into several smaller functions called in sequence;
- keeping your functions small enough so that they just do what their name says, and nothing more;
- implement English-like code that reads so naturally that even a child could understand what it does.
-
Even if you are on a hurry :
- immediately fix any design or implementation flaw you see, or else technical debt will accumulate and slow you down in the future.
- continue to develop clean maintainable code, this will actually allow you to ship faster by helping you maintain a high level of productivity while the project size grows over time.
-
Be a source of order instead of chaos, so always leave the code in a better state than you found it.
-
Make the application resilient to external conditions (network failures, missing or corrupted files, etc).
-
Check invalid method parameters with assertions in the debug build.
-
For performance reasons, preferably use :
- public attributes without getters and setters.
- public non-virtual methods.
- virtual methods instead of delegates.
- state classes instead of coroutines.
-
Use private attributes and methods only where you need to.
-
Create automated unit tests.
-
Only push stable tested code under source control, first test your changes extensively.
-
Use the concise functions provided by the project high level libraries instead of calling directly the low level functions they wrap.
-
Use American English everywhere.
InitializeColor(); MoveForward();
-
Use the English language order in compound identifiers.
enemy_list_by_category_dictionary = GetEnemyListByCategoryDictionary();
-
Use the meter as the default distance unit.
-
Use the second as the default time unit.
-
Use four spaces instead of tabulations, to make the code independent of the editor settings.
-
Use Unix line endings.
-
Trim trailing whitespace on save.
-
Choose short meaningful identifiers for class, attribute, method, constant and variable names, to prevent ambiguity and cognitive load.
-
Use standard prefixes :
- First, Last, Post
- Prior, Next
- Sub, Super, Base
- Initial, Final
- Old, New
- Backward, Forward
- Left, Right
- Back, Front
- Bottom, Top
- Minimum, Maximum
- Lower, Higher, Upper
- Horizontal, Vertical
- Local, Global
-
Use standard suffixes :
- Index, Count
- Array, List
- Map, Dictionary
-
Use standard verbs :
- Initialize, Update, Finalize
- Create, Release, Destroy
- Build, Apply
- Clear, Fill
- Reset, Set, Get, Find
- Is, Has
- Add, Remove
- AddFirst, RemoveFirst
- AddLast, RemoveLast
- Start, Stop
- Begin, End
- Enter, Exit
- Open, Close
- Read, Write
- Load, Save
- Pause, Resume
- Lock, Unlock
- Attach, Detach
- Enable, Disable
- Select, Deselect
- Activate, Deactivate
- Increment, Decrement
- Increase, Decrease
- Compress, Decompress
- Connect, Disconnect
- Send, Receive
- Grant, Revoke
-
Name your types (classes, structures, enumerations, etc) in SCREAMING_CASE, without articles.
class TANK_SHELL { VECTOR_3 PositionVector; QUATERNION RotationQuaternion; ... }
-
Name your type members (methods, attributes, constants, etc) in PascalCase, without articles.
ShootShell( Muzzle.PositionVector, Muzzle.RotationQuaternion );
-
Name your local variables and method parameters in snake_case, without articles.
void ShootShell( VECTOR_3 shell_position_vector, QUATERNION shell_rotation_quaternion ) { TANK_SHELL shot_tank_shell; ... shot_tank_shell = new TANK_SHELL( shell_position_vector, shell_rotation_quaternion ); ... }
-
Don't use abbreviations or single-letter variables.
TANK FindTank( int tank_identifier, int first_tank_index, int post_tank_index ) { int tank_index; for ( tank_index = first_tank_index; tank_index < post_tank_index; // no i, j, n, etc ++tank_index ) { if ( TankArray[ tank_index ].Identifier == tank_identifier ) { return TankArray[ tank_index ]; } } return null; }
-
Avoid acronyms, and capitalize them in member names.
DATABASE_URL DatabaseUrl;
-
If a variable name collides with a predefined identifier, simply add a trailing underscore.
CLASS class_; class_ = new CLASS();
-
Use a noun or noun phrase for classes, constants, attributes and variable names.
-
Include the meaningful part of the class name in attribute and variable names.
Dictionary<string, PLAYER> ActivePlayerDictionary; List<ENEMY> CloseEnemyList; TANK[] EnemyTankArray; VECTOR_3 InitialShellPositionVector, TankVelocityVector; void ShootShell( ) { SHELL last_shot_shell, shot_shell; ... }
-
Start method names with a verb in the imperative mood (Set, Get, Find, ...).
-
Start boolean inquiry names with a verb in the indicative mood (Is, Has, Can, ...).
-
Declare the method parameters in the same order as in the method name.
bool FindPlayerIndexByName( ref int player_index, string player_name ) { ... }
-
Use a positive affirmation for boolean variable and attribute names.
if ( game_is_paused ) { ... }
-
If an attribute name starts like its owner class name, omit the common prefix.
class TANK { TANK_SHELL[] ShellArray; bool IsDamaged; void ShootShell( TANK_SHELL tank_shell ) { ... } }
-
Align matching braces.
bool CanShoot( ) { return ShotShellCount < MaximumShellCount; } // ~~ void ShootShell( VECTOR_3 initial_velocity_vector ) { ... }
-
Use braces for single statement blocks.
if ( LoadedAmmunitionCount > 0 ) { ShootBullet(); } else if ( CarriedAmmunitionCount > 0 ) { ReloadWeapon(); } else { NoAmmunitionSound.Play(); }
-
Declare each attribute, variable and method parameter name on a separate line.
int tank_count, tank_index;
-
Try to declare all local variables at the start of the method, to improve the algorithm readability.
-
Group local variables of the same type, and sort the declarations by ascending types (lowercase, then PascalCase, then SCREAMING_CASE) and variable names, so that the declaration of a variable can be located at a glance.
int shell_count, shell_index, tank_count, tank_index; string player_name, target_name; CharacterController character_controller; NavMeshAgent navigation_mesh_agent; TANK enemy_tank; TANK[] enemy_tank_array;
-
Split complex statements and expressions on several lines if they contain boolean operators or if they become too wide.
-
When splitting an expression on several lines, start the next lines with an operator and align it with the start of its left operand (or else indent it by 4 spaces).
if ( ( tower.GetDistance( tower_target, weapon_type ) > tower.MaximumShootingDistance ) || ( tank_distance > maximum distance && tank_health > 0.5 ) ) { ... }
-
Favor indexed iterations over foreach iterations, and foreach iterations over functional iterations.
for ( enemy_index = 0; enemy_index < EnemyList.Count; ++enemy_index ) { ... } foreach ( ENEMY enemy in EnemyList ) { ... }
-
Put the scalar or constant multiplier after the multiplicand expression.
average_value = ( first_value + second_value ) * 0.5f;
-
Add exactly one space :
- after
(
[
,
- before
)
]
- after
if
switch
while
for
foreach
return
... - around operators.
- after
-
Add exactly one empty line :
- around standard comments;
- after the local variable declarations;
- after the method preconditions;
- between
if
switch
while
for
foreach
do
try
return
and the prior statement; - between
}
and the next statement.
-
Use standard file extensions.
- C# : cs
- C : c, h
- C++ : cpp, hpp
- Javascript : js
- HTML : html
- CSS : css
-
Declare one class per source code file.
-
Use the class name in lowercase as file name.
tank_shell.cpp tank_shell.hpp
-
Group the class elements by category, and declare them in this order :
- Imports.
- Types.
- Constants.
- Attributes.
- Constructors.
- Destructor.
- Operators.
- Inquiries : methods which don't change the class attributes.
- Operations : methods which may change the class attributes.
-
Within a category, declare :
- the called methods before the calling methods, preferably in the order they will be called, so that the class code can be immediately understood by a single sequential read.
- the static members after the non-static members.
-
Import exactly what each file needs to be compiled independently, and nothing more.
-
Sort the imports by ascending names.
-
Declare code sections in this order :
- imports
- constants
- types
- variables
- functions
- statements
-
Delimitate code sections with standard comments.
// -- IMPORTS ... // -- CONSTANTS ... // -- TYPES class NAME { // -- CONSTANTS ... // -- ATTRIBUTES ... // -- CONSTRUCTORS ... // -- DESTRUCTOR ... // -- OPERATORS ... // -- INQUIRIES ... // -- OPERATIONS ... } // -- VARIABLES ... // -- FUNCTIONS ... // -- STATEMENTS ...
-
Don't use standard comments for empty sections.
-
Align multiple lines comments with the surrounding statements, start them with an uppercase character and end them with a period.
/* A long explanation which must be written on several lines. */ ...
-
Align single line comments with the surrounding statements, start them with an uppercase character and end them with a period.
// A short explanation which can be written on a single line. ...
-
Put end of line comments exactly four spaces after the statement, and start them with lowercase character.
DoSomethingWeird(); // a short explanation
-
Name the unit test class by simply adding a
_TEST
suffix to the class name.
-
Begin header files with
#pragma once
.#pragma once // -- IMPORTS #include "tank.hpp" #include "tank_shell.hpp" // -- TYPES ...
-
Use double quotes for string literals.
-
Name your ids and classes in kebab-case, without articles.
-
Use :
- unitless values for line heights.
- rem values for font sizes and all other static sizes.
- px values only for tiny static sizes, like 1 or 2 pixels.
- %, vh, vw, vmin and vmax values for dynamic sizes.
- zero or one decimal in your sizes (0.9rem, 1.2vh), unless you absolutely need more precision (0.75rem, 1.25rem).
-
Group rules by category, and declare them in this order :
- Imports
- Constants
- Variables
- Functions
- Mixins
- Fonts
- Elements
- Classes
-
Delimitate rule sections with standard comments.
// -- IMPORTS ... // -- CONSTANTS ... // -- VARIABLES ... // -- FUNCTIONS ... // -- MIXINS ... // -- FONTS ... // -- ELEMENTS ... // -- CLASSES ...
-
Order rules by increasing interiority, appearance order, and specificity.
-
For a same base selector class, declare rules in this order :
- @keyframe class-animation
- .class
- .class:not()
- .class:first-child
- .class:nth-child()
- .class:last-child
- .class:hover
- .class:focus
- .class:active
- .class:invalid
- .class:before
- .class:after
- .class:placeholder-shown
- .class::placeholder
- .class ~ .other-class
- .class + .other-class
- .class > .other-class
- .class .other-class
- .class#id
- .class.other-class
-
Declare concatenated specifiers in this order :
- element
- #id
- .class
- :not()
- :first-child
- :nth-child()
- :last-child
- :hover
- :focus
- :active
- :invalid
- :before
- :after
- :placeholder-shown
- ::placeholder
-
Declare media queries inside the rule using the "+Media" mixin, right after the declarations, and order them by increasing breakpoint.
.class { ... +Media( min-width-40em ) { ... } +Media( min-width-60em ) { ... } +Media( min-width-80em, max-height-40em ) { ... } +Media( "min-width-80em && max-height-40em" ) { ... } +Media( "min-width-80em && min-height-40em", "max-width-120em && min-height-60em" ) { ... } +Media( "min-width-80em && min-height-40em", "max-width-120em && min-height-60em" ) { ... } }
-
Group declarations by category :
- Inheritance
- Position
- Container
- Layout
- Content
- Typography
- Behavior
-
Delimitate declaration sections with a blank line.
.header-menu { z-index: 100; position: fixed; top: 0; left: 0; right: 0; padding: 1rem; display: flex; justify-content: center; align-items: center; background-color: transparent; transition: background-color 0.3s ease; +Media( min-width-40em ) { padding: 2rem; } +Media( min-width-60em ) { padding: 3rem; } }
-
Declare properties in this order :
- Inheritance
- @extend
- Position
- z-index
- position
- top
- bottom
- left
- right
- transform-origin
- transform
- scale
- rotate
- translate
- Container
- container-type
- overflow
- overflow-y
- overflow-x
- box-sizing
- scrollbar-width
- inset
- margin
- margin-block
- margin-block-start
- margin-block-end
- margin-inline
- margin-inline-start
- margin-inline-end
- margin-top
- margin-bottom
- margin-left
- margin-right
- outline
- height
- min-height
- max-height
- width
- min-width
- max-width
- aspect-ratio
- border
- border-top
- border-bottom
- border-left
- border-right
- border-width
- border-style
- border-color
- border-image
- border-radius
- border-top-radius
- border-top-left-radius
- border-top-right-radius
- border-bottom-radius
- border-bottom-left-radius
- border-bottom-right-radius
- border-collapse
- padding
- padding-top
- padding-bottom
- padding-left
- padding-right
- Layout
- display
- flex
- flex-direction
- flex-wrap
- flex-grow
- flex-shrink
- flex-basis
- flex-flow
- grid-template
- grid-template-rows
- grid-template-columns
- grid-template-areas
- grid-auto-rows
- grid-gap
- gap
- row-gap
- column-gap
- grid-area
- grid-row
- grid-column
- justify-content
- justify-items
- justify-self
- align-content
- align-items
- align-self
- order
- float
- clear
- columns
- column-count
- column-width
- column-span
- column-fill
- column-gap
- column-rule
- column-rule-width
- column-rule-style
- column-rule-color
- shape-outside
- clip-path
- object-fit
- Content
- content
- visibility
- opacity
- background
- background-clip
- background-color
- background-image
- background-origin
- background-position
- background-repeat
- background-size
- background-attachment
- mask
- mask-clip
- mask-composite
- mask-image
- mask-mode
- mask-origin
- mask-position
- mask-repeat
- mask-size
- box-shadow
- filter
- backdrop-filter
- Typography
- list-style-type
- direction
- writing-mode
- text-orientation
- line-height
- font
- font-family
- font-size
- font-weight
- font-style
- font-stretch
- font-variant
- white-space
- overflow-wrap
- word-wrap
- word-break
- word-spacing
- letter-spacing
- caption-side
- vertical-align
- text-align
- text-align-last
- text-indent
- text-justify
- text-overflow
- text-decoration
- text-decoration-line
- text-decoration-style
- text-decoration-color
- text-transform
- text-shadow
- color
- Behavior
- resize
- scroll-behavior
- scroll-snap-type
- scroll-snap-points-y
- scroll-snap-points-x
- user-select
- pointer-events
- cursor
- transition
- transition-property
- transition-delay
- transition-duration
- transition-timing-function
- animation
- animation-name
- animation-delay
- animation-duration
- animation-timing-function
- animation-iteration-count
- animation-direction
- animation-fill-mode
- animation-play-state
- Media queries (of increasing breakpoint size)
- Inheritance
-
Write color literals in UPPERCASE.
background-color: #C8C8C8;
-
Declare Stylus constants in PascalCase.
RedColor = #F87272; RedColor100 = darken( RedColor, 80% );
-
Declare SCSS constants in kebab-case.
$red-color: #F87272; $red-color-100: mix( $red-color, #000000, 80% );
-
Use double quotes for string literals.
-
Use single quotes inside double-quoted string literals.
-
Declare tag attributes in this order :
- id
- class sorted by increasing specificity
- style sorted as explained above
- data-* in alphabetical order
- tag-specific attributes (src, href, etc) in alphabetical order
- on* in alphabetical order
<div id="header-menu-home-button" class="button scaled-button header-menu-button header-menu-home-button" style="margin-left: auto; background-image: url( '/static/image/header_menu/home_button.svg' )" data-view-name="home" onclick="ShowView( 'home' )"> ... </div>
-
Use the component name in lowercase as file name.
header_menu.pht
-
Declare component sections in this order :
- shared style
- inline style
- HTML template
- shared script
- inline script
-
Prefix all classes by the component name in kebab-case, and child classes by their parent class name.
<style file="header_menu.styl"> .header-menu { ... } .header-menu-button-container { ... } .header-menu-button { ... } .header-menu-button:hover, .header-menu-button.is-selected { ... } .header-menu-button-image { ... } .header-menu-button-text { ... } ... </style> <style> ... </style> <div id="header-menu" class="header-menu"> <div class="header-menu-button-container" <div class="header-menu-button" data-view-name="home" onclick="ShowView( 'home' )"> <img class="header-menu-button-image" src="/static/image/header_menu/home_button.svg"/> <span class="header-menu-button-text"> <# .GetText( 'HeaderMenuHomeButton' ) #> </span> </div> <div class="header-menu-button" data-view-name="contact" onclick="HandleHeaderMenuButtonClickEvent( event.currentTarget )"> <img class="header-menu-button-image" src="/static/image/header_menu/contact_button.svg"/> <span class="header-menu-button-text"> <# .GetText( 'HeaderMenuContactButton' ) #> </span> </div> ... </div> </div> <script file="header_menu.js"> // -- FUNCTIONS function HandleHeaderMenuButtonClickEvent( header_menu_button_element ) { ShowView( header_menu_button_element.dataset.viewName ); } </script> <script> ... </script>
-
Use single quotes for string literals.
-
Use double quotes for interpolated string literals.
-
Use the class name in uppercase as Unity file name.
TANK_SHELL.cs
-
Name your scene assets and files in PascalCase.
- Name types in PascalCase;
- Name type members, functions, function parameters and local variables in snake_case.
- Declare variables dynamically.
- Use single quotes for string literals.
1.2
Eric Pelzer (ecstatic.coder@gmail.com).
This project is licensed under the GNU Lesser General Public License version 3.
See the LICENSE.md file for details.