{"name":"Code Best Practices","title":"Code Best Practices","type":"topic","url":"https://community.bistudio.com/wiki/Code_Best_Practices","revid":369844,"updated":"2024-10-16T13:51:56Z","aliases":[],"markdown":"### Getting Started\n\nIn the domain of development, any rule is a rule of thumb.\nIf a rule states for example that it is better that a line of code doesn't go over 80 characters, it doesn't mean that any line ***must not*** go over 80 characters; sometimes, the situation needs it.\nIf you have a good structure, **do not** change your code to enforce a single arbitrary rule.\nIf you break many of them, you may have to change something; again, this is according to your judgement.\n\nWith that being said, let's go!\n\n#### Prerequisites\n\n- An advanced text editor such as Visual Studio Code or Notepad++ - see Community Tools#Code Edition for useful tools and plugins\n- Some English knowledge, helped if needed by a translator tool such as [Google Translate](https://www.google.com/translate) or [DeepL](https://www.deepl.com/)\n- Access to this wiki is a plus (the Swiss flag is, too)\n- Tutorials/examples (YouTube tutorials, community tutorials, Example Code)\n- Google-Fu (a.k.a search engine skills)\n- Arma Discord server: [ARMA](https://discord.gg/arma), channel `1. arma3_scripting`\n\n### Best Practices\n\n#### Code Format\n\n- Whatever you do about your code's format, **be consistent**.\n- Choose an indentation format **and stick to it**. There is not especially one indent better than another (*but there sure are terrible ones*), again the important point here being *consistency*.\n  - Common indentation styles are:\n    - [K&R style](https://en.wikipedia.org/wiki/Indentation_style#K&R_style) indenting\n    - [Allman style](https://en.wikipedia.org/wiki/Indentation_style#Allman_style) indenting\n  - Use empty space. Line return, spaces before and after brackets, if this improves readability, use it: space is free.\n  - indent with two/four spaces **or** one tab. Do not mix these.\n  - *One-lining* (putting everything in one statement) memory improvement is most of the time not worth the headache it gives when trying to read it. Don't overuse it.\n-  **was** \"useful\" only for editor fields that for no apparent reason refused commands returning a value. You do **not** need it in script files, and don't need it in editor fields anymore **since Arma 3 v2.04**.\n\n#### Variable Format\n\n- Name your variables and functions properly: While SQF *is* (non-noticeably) impacted by variable name length, this should not take precedence on the fact that code must be readable by a human being.\n  - Your variable names must have a meaning: variables like **_u** instead of **_uniform** should not exist. **_i** is an accepted iteration variable name (e.g in for loops).\n  - It is recommended to use [camel-case](https://en.wikipedia.org/wiki/Camel_case) your variables; camel-casing (namingLikeThis) your variables and functions make the code naturally more readable, especially for long names.\n- Prefix your public variables and setVariable with your tag in order to avoid any conflict about other mods, scripts or mission variables.\n- Make your variables **private** thanks to the private or params keyword in order to avoid accidental upper-scope overwriting of variables of the same name.\n- Defined constants must be UPPERCASE_WITH_UNDERSCORES (e.g `#define SOME_CONST`).\n\n#### Code Structuration\n\n- **DRY:** **D**on't **R**epeat **Y**ourself. If you write the same code block or the same logic many times, export this code as a function and use parameters with it.\n  - If your code has too many levels, it is time to split and rethink it - maybe using exitWith (e.g `if (a) then { if (b) then { if (c) then { /* etc */  }; }; };`)\n  - Do NOT use macros as functions - these hinder readability. Use functions instead.\n- `// Comments` in your code must not explain *what* the code does, but *why* it is done this way (if needed). Your code organisation combined to your variable names must be enough to be read by a human.\n\n#### Code/Files Organisation\n\n- Use CfgFunctions to declare the functions that will be called frequently.\n  - One Functions directory, with sub-directories if needed.\n- Use Event Scripts as needed.\n- Don't put **any code** in a unit's init box *but eventually* local commands for this specific unit - **all** unit's init boxes are run client-side on client connection.\n\n### Examples\n\n| Bad Example | Good Example |\n|---|---|\n| #### Good Practice examples |  |\n| _unit = player; | **private** _unit = player; |\n| private _uB = allUnits select { side _x == blufor }; | private **_bluforUnits** = allUnits select { side _x == blufor }; |\n| private _plead = leader player; | private **_playersLeader** = leader player; |\n| finalAssault = true; publicVariable \"finalAssault\"; | **PREFIX_**finalAssault = true; publicVariable \"**PREFIX_**finalAssault\"; |\n| player setVariable [\"MoneyInPocket\", 250, true]; | player setVariable [\"**PREFIX_**MoneyInPocket\", 250, true]; |\n| #define KILL(UNIT) UNIT setDamage 1<br> // ...<br> {<br> \tKILL(_x);<br> } forEach (units group player - [player]); | private _killFnc = { _this setDamage 1; };<br> // ...<br> {<br> \t_x call _killFnc;<br> } forEach (units group player - [player]); |\n| `// if player has less than 3/4 health`<br> if (damage player > 0.25) then<br> {<br> \t`// if the player has no first aid kit`<br> \tif (not (\"FirstAidKit\" in items player))<br> \t{<br> \t\t`// if player has room for first aid kit`<br> \t\tif (player canAdd \"FirstAidKit\") then<br> \t\t{<br> \t\t\t `// add first aid kit to the player`<br> \t\t\tplayer addItem \"FirstAidKit\";<br> \t\t}<br> \t\telse<br> \t\t{<br> \t\t\t`// set player's damage to 1/4`<br> \t\t\tplayer setDamage 0.25;<br> \t\t};<br> \t};<br> }; | `// player will need health at this stage of the mission`<br> if (<br> \tdamage player > 0.25 &&<br> \tnot (\"FirstAidKit\" in items player)) then<br> {<br> \tif (player canAdd \"FirstAidKit\") then<br> \t{<br> \t\tplayer addItem \"FirstAidKit\";<br> \t}<br> \telse `// let's help him anyway`<br> \t{<br> \t\tplayer setDamage 0.25;<br> \t};<br> }; |\n| #### Flow Logic examples |  |\n| if (alive player && damage player >= 0.9) then {<br> \thint \"very damaged\";<br> };<br> if (alive player && damage player >= 0.5 && damage player < 0.9) then {<br> \thint \"quite damaged\";<br> };<br> if (alive player && damage player > 0 && damage player < 0.5) then {<br> \thint \"slightly damaged\";<br> };<br> if (alive player && damage player == 0) then {<br> \thint \"pristine state\";<br> };<br> if (not alive player) then {<br> \thint \"dead\";<br> }; | if (not alive player) exitWith { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> \tcase (_playerDamage >= 0.9): { hint \"very damaged\"; };<br> \tcase (_playerDamage >= 0.5): { hint \"quite damaged\"; };<br> \tcase (_playerDamage > 0)   : { hint \"slightly damaged\"; };<br> \tdefault { hint \"pristine\"; };<br> }; |\n| if (cond1) then<br> {<br> \tif (cond2) then<br> \t{<br> \t\tif (cond3) then<br> \t\t{<br> \t\t\t// hadouken code<br> \t\t}<br> \t\telse { `/* failure 3 */` };<br> \t}<br> \telse { `/* failure 2 */` };<br> }<br> else { `/* failure 1 */` }; | if (!cond1) exitWith { `/* failure 1 */` };<br> if (!cond2) exitWith { `/* failure 2 */` };<br> if (!cond3) exitWith { `/* failure 3 */` };<br> // code |\n| #### Format examples |  |\n| if (not alive player) exitWith<br> { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> case (_playerDamage >= 0.9): {hint \"very damaged\";};<br> case (_playerDamage >= 0.5): {<br> \thint  \"quite damaged\";};<br> case (_playerDamage > 0): { hint \"slightly damaged\"; };<br>   default<br> {<br>    hint \"pristine\";<br>   };<br> }; | if (not alive player) exitWith { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> \tcase (_playerDamage >= 0.9): { hint \"very damaged\"; };<br> \tcase (_playerDamage >= 0.5): { hint \"quite damaged\"; };<br> \tcase (_playerDamage > 0)   : { hint \"slightly damaged\"; };<br> \tdefault { hint \"pristine\"; };<br> }; |\n\n### Final Words\n\n- Remember: **consistency** is the most important thing!\n- The Arma Discord server and its community can help: [ARMA](https://discord.gg/arma) (channel `1. arma3_scripting`)\n- Learn from others's scripts but do not steal code and pretend it is yours — be a decent human being. Stealing code and its consequences:\n  - It soils your reputation and devaluates your actions once it is found out — and it *always* get found out. DMCA's are filled on Steam every day.\n  - It makes people in the community get less helpful and more reluctant in giving advices. It can also prevent them to *release* an interesting feature!\n- Don't try to obfuscate your code: it is considered rude, especially since you learnt from others.\n  - Obfuscated code only makes it *harder* to get, but does not make it *copy-protected*. If the engine can read it, it can be obtained.\n  - Obfuscated code is also slower on parsing and, depending on the quality of code and obfuscation, on execution too.\n- Do not hesitate to help newcomers even if you do not know the whole topic: both sides will learn from it!\n- Most important of all, have fun!\n\n### See also\n\n- Code Optimisation\n- Code Positivity\n- Mission Optimisation\n- Multiplayer Scripting","sections":[{"heading":"Getting Started","level":3,"markdown":"In the domain of development, any rule is a rule of thumb.\nIf a rule states for example that it is better that a line of code doesn't go over 80 characters, it doesn't mean that any line ***must not*** go over 80 characters; sometimes, the situation needs it.\nIf you have a good structure, **do not** change your code to enforce a single arbitrary rule.\nIf you break many of them, you may have to change something; again, this is according to your judgement.\n\nWith that being said, let's go!"},{"heading":"Prerequisites","level":4,"markdown":"- An advanced text editor such as Visual Studio Code or Notepad++ - see Community Tools#Code Edition for useful tools and plugins\n- Some English knowledge, helped if needed by a translator tool such as [Google Translate](https://www.google.com/translate) or [DeepL](https://www.deepl.com/)\n- Access to this wiki is a plus (the Swiss flag is, too)\n- Tutorials/examples (YouTube tutorials, community tutorials, Example Code)\n- Google-Fu (a.k.a search engine skills)\n- Arma Discord server: [ARMA](https://discord.gg/arma), channel `1. arma3_scripting`"},{"heading":"Best Practices","level":3,"markdown":""},{"heading":"Code Format","level":4,"markdown":"- Whatever you do about your code's format, **be consistent**.\n- Choose an indentation format **and stick to it**. There is not especially one indent better than another (*but there sure are terrible ones*), again the important point here being *consistency*.\n  - Common indentation styles are:\n    - [K&R style](https://en.wikipedia.org/wiki/Indentation_style#K&R_style) indenting\n    - [Allman style](https://en.wikipedia.org/wiki/Indentation_style#Allman_style) indenting\n  - Use empty space. Line return, spaces before and after brackets, if this improves readability, use it: space is free.\n  - indent with two/four spaces **or** one tab. Do not mix these.\n  - *One-lining* (putting everything in one statement) memory improvement is most of the time not worth the headache it gives when trying to read it. Don't overuse it.\n-  **was** \"useful\" only for editor fields that for no apparent reason refused commands returning a value. You do **not** need it in script files, and don't need it in editor fields anymore **since Arma 3 v2.04**."},{"heading":"Variable Format","level":4,"markdown":"- Name your variables and functions properly: While SQF *is* (non-noticeably) impacted by variable name length, this should not take precedence on the fact that code must be readable by a human being.\n  - Your variable names must have a meaning: variables like **_u** instead of **_uniform** should not exist. **_i** is an accepted iteration variable name (e.g in for loops).\n  - It is recommended to use [camel-case](https://en.wikipedia.org/wiki/Camel_case) your variables; camel-casing (namingLikeThis) your variables and functions make the code naturally more readable, especially for long names.\n- Prefix your public variables and setVariable with your tag in order to avoid any conflict about other mods, scripts or mission variables.\n- Make your variables **private** thanks to the private or params keyword in order to avoid accidental upper-scope overwriting of variables of the same name.\n- Defined constants must be UPPERCASE_WITH_UNDERSCORES (e.g `#define SOME_CONST`)."},{"heading":"Code Structuration","level":4,"markdown":"- **DRY:** **D**on't **R**epeat **Y**ourself. If you write the same code block or the same logic many times, export this code as a function and use parameters with it.\n  - If your code has too many levels, it is time to split and rethink it - maybe using exitWith (e.g `if (a) then { if (b) then { if (c) then { /* etc */  }; }; };`)\n  - Do NOT use macros as functions - these hinder readability. Use functions instead.\n- `// Comments` in your code must not explain *what* the code does, but *why* it is done this way (if needed). Your code organisation combined to your variable names must be enough to be read by a human."},{"heading":"Code/Files Organisation","level":4,"markdown":"- Use CfgFunctions to declare the functions that will be called frequently.\n  - One Functions directory, with sub-directories if needed.\n- Use Event Scripts as needed.\n- Don't put **any code** in a unit's init box *but eventually* local commands for this specific unit - **all** unit's init boxes are run client-side on client connection."},{"heading":"Examples","level":3,"markdown":"| Bad Example | Good Example |\n|---|---|\n| #### Good Practice examples |  |\n| _unit = player; | **private** _unit = player; |\n| private _uB = allUnits select { side _x == blufor }; | private **_bluforUnits** = allUnits select { side _x == blufor }; |\n| private _plead = leader player; | private **_playersLeader** = leader player; |\n| finalAssault = true; publicVariable \"finalAssault\"; | **PREFIX_**finalAssault = true; publicVariable \"**PREFIX_**finalAssault\"; |\n| player setVariable [\"MoneyInPocket\", 250, true]; | player setVariable [\"**PREFIX_**MoneyInPocket\", 250, true]; |\n| #define KILL(UNIT) UNIT setDamage 1<br> // ...<br> {<br> \tKILL(_x);<br> } forEach (units group player - [player]); | private _killFnc = { _this setDamage 1; };<br> // ...<br> {<br> \t_x call _killFnc;<br> } forEach (units group player - [player]); |\n| `// if player has less than 3/4 health`<br> if (damage player > 0.25) then<br> {<br> \t`// if the player has no first aid kit`<br> \tif (not (\"FirstAidKit\" in items player))<br> \t{<br> \t\t`// if player has room for first aid kit`<br> \t\tif (player canAdd \"FirstAidKit\") then<br> \t\t{<br> \t\t\t `// add first aid kit to the player`<br> \t\t\tplayer addItem \"FirstAidKit\";<br> \t\t}<br> \t\telse<br> \t\t{<br> \t\t\t`// set player's damage to 1/4`<br> \t\t\tplayer setDamage 0.25;<br> \t\t};<br> \t};<br> }; | `// player will need health at this stage of the mission`<br> if (<br> \tdamage player > 0.25 &&<br> \tnot (\"FirstAidKit\" in items player)) then<br> {<br> \tif (player canAdd \"FirstAidKit\") then<br> \t{<br> \t\tplayer addItem \"FirstAidKit\";<br> \t}<br> \telse `// let's help him anyway`<br> \t{<br> \t\tplayer setDamage 0.25;<br> \t};<br> }; |\n| #### Flow Logic examples |  |\n| if (alive player && damage player >= 0.9) then {<br> \thint \"very damaged\";<br> };<br> if (alive player && damage player >= 0.5 && damage player < 0.9) then {<br> \thint \"quite damaged\";<br> };<br> if (alive player && damage player > 0 && damage player < 0.5) then {<br> \thint \"slightly damaged\";<br> };<br> if (alive player && damage player == 0) then {<br> \thint \"pristine state\";<br> };<br> if (not alive player) then {<br> \thint \"dead\";<br> }; | if (not alive player) exitWith { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> \tcase (_playerDamage >= 0.9): { hint \"very damaged\"; };<br> \tcase (_playerDamage >= 0.5): { hint \"quite damaged\"; };<br> \tcase (_playerDamage > 0)   : { hint \"slightly damaged\"; };<br> \tdefault { hint \"pristine\"; };<br> }; |\n| if (cond1) then<br> {<br> \tif (cond2) then<br> \t{<br> \t\tif (cond3) then<br> \t\t{<br> \t\t\t// hadouken code<br> \t\t}<br> \t\telse { `/* failure 3 */` };<br> \t}<br> \telse { `/* failure 2 */` };<br> }<br> else { `/* failure 1 */` }; | if (!cond1) exitWith { `/* failure 1 */` };<br> if (!cond2) exitWith { `/* failure 2 */` };<br> if (!cond3) exitWith { `/* failure 3 */` };<br> // code |\n| #### Format examples |  |\n| if (not alive player) exitWith<br> { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> case (_playerDamage >= 0.9): {hint \"very damaged\";};<br> case (_playerDamage >= 0.5): {<br> \thint  \"quite damaged\";};<br> case (_playerDamage > 0): { hint \"slightly damaged\"; };<br>   default<br> {<br>    hint \"pristine\";<br>   };<br> }; | if (not alive player) exitWith { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> \tcase (_playerDamage >= 0.9): { hint \"very damaged\"; };<br> \tcase (_playerDamage >= 0.5): { hint \"quite damaged\"; };<br> \tcase (_playerDamage > 0)   : { hint \"slightly damaged\"; };<br> \tdefault { hint \"pristine\"; };<br> }; |"},{"heading":"Final Words","level":3,"markdown":"- Remember: **consistency** is the most important thing!\n- The Arma Discord server and its community can help: [ARMA](https://discord.gg/arma) (channel `1. arma3_scripting`)\n- Learn from others's scripts but do not steal code and pretend it is yours — be a decent human being. Stealing code and its consequences:\n  - It soils your reputation and devaluates your actions once it is found out — and it *always* get found out. DMCA's are filled on Steam every day.\n  - It makes people in the community get less helpful and more reluctant in giving advices. It can also prevent them to *release* an interesting feature!\n- Don't try to obfuscate your code: it is considered rude, especially since you learnt from others.\n  - Obfuscated code only makes it *harder* to get, but does not make it *copy-protected*. If the engine can read it, it can be obtained.\n  - Obfuscated code is also slower on parsing and, depending on the quality of code and obfuscation, on execution too.\n- Do not hesitate to help newcomers even if you do not know the whole topic: both sides will learn from it!\n- Most important of all, have fun!"},{"heading":"See also","level":3,"markdown":"- Code Optimisation\n- Code Positivity\n- Mission Optimisation\n- Multiplayer Scripting"}],"categories":["Arma Scripting Tutorials"],"groups":["Scripting"]}