e5dbc9c06e1dda2183cfeda0cc59943d1a7442da
[csit.git] / docs / bash_code_style.rst
1 ..
2    Copyright (c) 2019 Cisco and/or its affiliates.
3    Licensed under the Apache License, Version 2.0 (the "License");
4    you may not use this file except in compliance with the License.
5    You may obtain a copy of the License at:
6 ..
7        http://www.apache.org/licenses/LICENSE-2.0
8 ..
9    Unless required by applicable law or agreed to in writing, software
10    distributed under the License is distributed on an "AS IS" BASIS,
11    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12    See the License for the specific language governing permissions and
13    limitations under the License.
14
15
16 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
17 "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED",
18 "MAY", and "OPTIONAL" in this document are to be interpreted as
19 described in `BCP 14 <https://tools.ietf.org/html/bcp14>`_
20 `[RFC2119] <https://tools.ietf.org/html/rfc2119>`_
21 `[RFC8174] <https://tools.ietf.org/html/rfc8174>`_
22 when, and only when, they appear in all capitals, as shown here.
23
24 This document SHALL describe guidelines for writing reliable, maintainable,
25 reusable and readable code for CSIT.
26
27 Motivation
28 ^^^^^^^^^^
29
30 TODO: List reasons why we need code style document for Bash.
31
32 Proposed style
33 ^^^^^^^^^^^^^^
34
35 File types
36 ~~~~~~~~~~
37
38 Bash files SHOULD NOT be monolithic. Generally, this document
39 considers two types of bash files:
40
41 + Entry script: Assumed to be called by user,
42   or a script "external" in some way.
43
44   + Sources bash libraries and calls functions defined there.
45
46 + Library file: To be sourced by entry scipts, possibly also by other libraries.
47
48   + Sources other libraries for functions it needs.
49
50     + Or relies on a related file already having sourced that.
51
52     + Documentation SHALL imply which case it is.
53
54   + Defines multiple functions other scripts can call.
55
56 Safety
57 ~~~~~~
58
59 + Variable expansions MUST be quoted, to prevent word splitting.
60
61   + This includes special "variables" such as "${1}".
62
63     + RECOMMENDED even if the value is safe, as in "$?" and "$#".
64
65   + It is RECOMMENDED to quote strings in general,
66     so text editors can syntax-highlight them.
67
68     + Even if the string is a numeric value.
69
70     + Commands and known options can get their own highlight, no need to quote.
71
72       + Example: You do not need to quote every word of
73         "pip install --upgrade virtualenv".
74
75   + Code SHALL NOT quote glob characters you need to expand (obviously).
76
77     + OPTIONALLY do not quote adjacent characters (such as dot or fore-slash),
78       so that syntax highlighting makes them stand out compared to surrounding
79       ordinary strings.
80
81     + Example: cp "logs"/*."log" "."/
82
83     + TODO: Consider giving examples both for good and bad usage.
84
85   + Command substitution on right hand side of assignment should be safe
86     without quotes.
87
88     + But still, quotes are RECOMMENDED, unless line length is a concern.
89
90     + Note that command substitution limits the scope for quotes,
91       so it is NOT REQUIRED to escape the quotes in deeper levels.
92
93     + TODO: Do we prefer backtics, or "dollar round-bracket"?
94
95       + Backticks are more readable, especially when there are
96         round brackets in the surrounding text.
97
98       + Backticks do not allow nested command substitution.
99
100         + But we might want to avoid nested command substitution anyway?
101
102   + Code SHOULD NOT be structured in a way where
103     word splitting is intended.
104
105     + Example: Variable holding string of multiple command lines arguments.
106
107     + Solution: Array variable should be used in this case.
108
109     + Expansion MUST use quotes then: "${name[@]}".
110
111     + Word splitting MAY be used when creating arrays from command substitution.
112
113 + Code MUST always check the exit code of commands.
114
115   + Traditionally, error code checking is done either by "set -e"
116     or by appending "|| die" after each command.
117     The first is unreliable, due to many rules affecting "set -e" behavior
118     (see <https://mywiki.wooledge.org/BashFAQ/105>), but "|| die"
119     relies on humans identifying each command, which is also unreliable.
120     When was the last time you checked error code of "echo" command,
121     for example?
122
123     + Another example: "set -e" in your function has no effect
124       if any ancestor call is done with logical or,
125       for example in "func || code=$?" construct.
126
127   + As there is no reliable method of error detection, and there are two
128     largely independent unreliable methods, the best what we can do
129     is to apply both. So, code SHOULD explicitly
130     check each command (with "|| die" and similar) AND have "set -e" applied.
131
132   + Code MUST explicitly check each command, unless the command is well known,
133     and considered safe (such as the aforementioned "echo").
134
135     + The well known commands MUST still be checked implicitly via "set -e".
136
137   + See below for specific "set -e" recommendations.
138
139 + Code SHOULD use "readlink -e" (or "-f" if target does not exist yet)
140   to normalize any path value to absolute path without symlinks.
141   It helps with debugging and identifies malformed paths.
142
143 + Code SHOULD use such normalized paths for sourcing.
144
145 + When exiting on a known error, code MUST print a longer, helpful message,
146   in order for the user to fix their situation if possible.
147
148 + When error happens at an unexpected place, it is RECOMMENDED for the message
149   to be short and generic, instead of speculative.
150
151 Bash options
152 ~~~~~~~~~~~~
153
154 + Code MUST apply "-x" to make debugging easier.
155
156   + Code MAY temporarily supress such output in order to avoid spam
157     (e.g. in long busy loops), but it is still NOT RECOMMENDED to do so.
158
159 + Code MUST apply "-e" for early error detection.
160
161   + But code still SHOULD use "|| die" for most commands,
162     as "-e" has numerous rules and exceptions.
163
164   + Code MAY apply "+e" temporarily for commands which (possibly nonzero)
165     exit code it interested in.
166
167     + Code MUST to store "$?" and call "set -e" immediatelly afterwards.
168
169     + Code MUST NOT use this approach when calling functions.
170
171       + That is because functions are instructed to apply "set -e" on their own
172         which (when triggered) will exit the whole entry script.
173
174         + Unless overriden by ERR trap.
175           But code SHOULD NOT set any ERR trap.
176
177       + If code needs exit code of a function, it is RECOMMENDED to use
178         pattern 'code="0"; called_function || code="${?}"'.
179
180         + In this case, contributor MUST make sure nothing in the
181           called_function sub-graph relies on "set -e" behavior,
182           because the call being part of "or construct" disables it.
183
184   + Code MAY append "|| true" for benign commands,
185     when it is clear non-zero exit codes make no difference.
186
187     + Also in this case, the contributor MUST make sure nothing within
188       the called sub-graph depends on "set -e", as it is disabled.
189
190 + Code MUST apply "-u" as unset variable is generally a typo, thus an error.
191
192   + Code MAY temporarily apply "+u" if a command needs that to pass.
193
194     + Virtualenv activation is the only known example so far.
195
196 + Code MUST apply "-o pipefail" to make sure "-e" picks errors
197   inside piped construct.
198
199   + Code MAY use "|| true" inside a pipe construct, in the (inprobable) case
200     when non-zero exit code still results in a meaningful pipe output.
201
202 + All together: "set -exuo pipefail".
203
204   + Code MUST put that line near start of every file, so we are sure
205     the options are applied no matter what.
206
207     + "Near start" means "before any nontrivial code".
208
209     + Basically only copyright is RECOMMENDED to appear before.
210
211   + Also code MUST put the line near start of function bodies
212     and subshell invocations.
213
214 Functions
215 ~~~~~~~~~
216
217 There are (at least) two possibilities how a code from an external file
218 can be executed. Either the file contains a code block to execute
219 on each "source" invocation, or the file just defines functions
220 which have to be called separately.
221
222 This document considers the "function way" to be better,
223 here are some pros and cons:
224
225 + Cons:
226
227   + The function way takes more space. Files have more lines,
228     and the code in function body is one indent deeper.
229
230   + It is not easy to create functions for low-level argument manipulation,
231     as "shift" command in the function code does not affect the caller context.
232
233   + Call sites frequently refer to code two times,
234     when sourcing the definition and when executing the function.
235
236   + It is not clear when a library can rely on its relative
237     to have performed the sourcing already.
238
239   + Ideally, each library should detect if it has been sourced already
240     and return early, which takes even more space.
241
242 + Pros:
243
244   + Some code blocks are more useful when used as function,
245     to make call site shorter.
246
247     + Examples: Trap functions, "die" function.
248
249   + The "import" part and "function" part usually have different side effects,
250     making the documentation more focused (even if longer overall).
251
252   + There is zero risk of argument-less invocation picking arguments
253     from parent context.
254
255     + This safety feature is the main reason for chosing the "function way".
256
257     + This allows code blocks to support optional arguments.
258
259 + Rules:
260
261   + Library files MUST be only "source"d. For example if "tox" calls a script,
262     it is an entry script.
263
264   + Library files (upon sourcing) MUST minimize size effect.
265
266     + The only permitted side effects MUST by directly related to:
267
268       + Defining functions (without executing them).
269
270       + Sourcing sub-library files.
271
272   + If a bash script indirectly call another bash script,
273     it is not a "source" operation, variables are not shared,
274     so the called script MUST be considered an entry script,
275     even if it implements logic fitting into a single function.
276
277   + Entry scripts SHOULD avoid duplicating any logic.
278
279     + Clear duplicated blocks MUST be moved into libraries as functions.
280
281     + Blocks with low amount of duplication MAY remain in entry scripts.
282
283     + Usual motives for not creating functions are:
284
285       + The extracted function would have too much logic for processing
286         arguments (instead of hardcoding values as in entry script).
287
288       + The arguments needed would be too verbose.
289
290         + And using "set +x" would take too much vertical space
291           (when compared to entry script implementation).
292
293 Variables
294 ~~~~~~~~~
295
296 This document describes two kinds of variables: called "local" and "global".
297
298 TODO: Find better adjectives for the two kinds defined here,
299 if the usual bash meaning makes reader forget other specifics.
300 For example, variable with lowercase name and not marked by "local" builtin,
301 is cosidered "global" from bash point of view, but "local" from this document
302 point of view.
303
304 + Local variables:
305
306   + Variable name MUST contain only lower case letters, digits and underscores.
307
308   + Code MUST NOT export local variables.
309
310   + Code MUST NOT rely on local variables set in different contexts.
311
312   + Documentation is NOT REQUIRED.
313
314     + Variable name SHOULD be descriptive enough.
315
316   + Local variable MUST be initialized before first use.
317
318     + Code SHOULD have a comment if a reader might have missed
319       the initialization.
320
321   + TODO: Agree on level of defensiveness (against local values
322     being influenced by other functions) needed.
323     Possible alternatives / additions to the "always initialize" rule:
324
325     + Unset local variables when leaving the function.
326
327     + Explicitly typeset by "local" builtin command.
328
329     + Require strict naming convention, e.g. function_name__variable_name.
330
331 + Global variables:
332
333   + Variable name MUST contain only upper case letters, digits and underscores.
334
335   + They SHOULD NOT be exported, unless external commands need them
336     (e.g. PYTHONPATH).
337
338   + TODO: Propose a strict naming convention, or a central document
339     of all used global variables, to prevent contributors
340     from causing variable name conflicts.
341
342   + Code MUST document if a function (or its inner call)
343     reads a global variable.
344
345   + Code MUST document if a function (or its inner call)
346     sets or rewrites a global variable.
347
348   + If a function "wants to return a value", it SHOULD be implemented
349     as the function setting (or rewriting) a global variable,
350     and the call sites reading that variable.
351
352   + If a function "wants to accept an argument", it IS RECOMMENDED
353     to be implemented as the call sites setting or rewriting global variables,
354     and the function reading that variables.
355     But see below for direct arguments.
356
357 + Code MUST use curly brackets when referencing variables,
358   e.g. "${my_variable}".
359
360   + It makes related constructs (such as ${name:-default}) less surprising.
361
362   + It looks more similar to Robot Framework variables (which is good).
363
364 Arguments
365 ~~~~~~~~~
366
367 Bash scripts and functions MAY accept arguments, named "${1}", "${2}" and so on.
368 As a whole available via "$@".
369 You MAY use "shift" command to consume an argument.
370
371 Contexts
372 ````````
373
374 Functions never have access to parent arguments, but they can read and write
375 variables set or read by parent contexts.
376
377 Arguments or variables
378 ``````````````````````
379
380 + Both arguments and global variables MAY act as an input.
381
382 + In general, if the caller is likely to supply the value already placed
383   in a global variable of known name, it is RECOMMENDED
384   to use that global variable.
385
386 + Construct "${NAME:-value}" can be used equally well for arguments,
387   so default values are possible for both input methods.
388
389 + Arguments are positional, so there are restrictions on which input
390   is optional.
391
392 + Functions SHOULD either look at arguments (possibly also
393   reading global variables to use as defaults), or look at variables only.
394
395 + Code MUST NOT rely on "${0}", it SHOULD use "${BASH_SOURCE[0]}" instead
396   (and apply "readlink -e") to get the current block location.
397
398 + For entry scripts, it is RECOMMENDED to use standard parsing capabilities.
399
400   + For most Linux distros, "getopt" is RECOMMENDED.
401
402 Working directory handling
403 ~~~~~~~~~~~~~~~~~~~~~~~~~~
404
405 + Functions SHOULD act correctly without neither assuming
406   what the currect working directory is, nor changing it.
407
408   + That is why global variables and arguments SHOULD contain
409     (normalized) full paths.
410
411   + Motivation: Different call sites MAY rely on different working directories.
412
413 + A function MAY return (also with nonzero exit code) when working directory
414   is changed.
415
416   + In this case the function documentation MUST clearly state where (and when)
417     is the working directory changed.
418
419     + Exception: Functions with undocumented exit code.
420
421     + Those functions MUST return nonzero code only on "set -e" or "die".
422
423       + Note that both "set -e" and "die" by default result in exit of the whole
424         entry script, but the caller MAY have altered that behavior
425         (by registering ERR trap, or redefining die function).
426
427     + Any callers which use "set +e" or "|| true" MUST make sure
428       their (and their caller ancestors') assumption on working directory
429       are not affected.
430
431       + Such callers SHOULD do that by restoring the original working directory
432         either in their code,
433
434       + or contributors SHOULD do such restoration in the function code,
435         (see below) if that is more convenient.
436
437   + Motivation: Callers MAY rely on this side effect to simplify their logic.
438
439 + A function MAY assume a particular directory is already set
440   as the working directory (to save space).
441
442   + In this case function documentation MUST clearly state what the assumed
443     working directory is.
444
445   + Motivation: Callers MAY call several functions with common
446     directory of interest.
447
448     + Example: Several dowload actions to execute in sequence,
449       implemented as functions assuming ${DOWNLOAD_DIR}
450       is the working directory.
451
452 + A function MAY change the working directory transiently,
453   before restoring it back before return.
454
455   + Such functions SHOULD use command "pushd" to change the working directory.
456
457   + Such functions SHOULD use "trap 'trap - RETURN; popd' RETURN"
458     imediately after the pushd.
459
460     + In that case, the "trap - RETURN" part MUST be included,
461       to restore any trap set by ancestor.
462
463     + Functions MAY call "trap - RETURN; popd" exlicitly.
464
465     + Such functions MUST NOT call another pushd (before an explicit popd),
466       as traps do not stack within a function.
467
468 + If entry scripts also use traps to restore working directory (or other state),
469   they SHOULD use EXIT traps instead.
470
471   + That is because "exit" command, as well as the default behavior
472     of "die" or "set -e" cause direct exit (without skipping function returns).
473
474 Function size
475 ~~~~~~~~~~~~~
476
477 + In general, code SHOULD follow reasoning similar to how pylint
478   limits code complexity.
479
480 + It is RECOMMENDED to have functions somewhat simpler than Python functions,
481   as Bash is generally more verbose and less readable.
482
483 + If code contains comments in order to partition a block
484   into sub-blocks, the sub-blocks SHOULD be moved into separate functions.
485
486   + Unless the sub-blocks are essentially one-liners,
487     not readable just because external commands do not have
488     obvious enough parameters. Use common sense.
489
490 Documentation
491 ~~~~~~~~~~~~~
492
493 + The library path and filename is visible from source sites. It SHOULD be
494   descriptive enough, so reader do not need to look inside to determine
495   how and why is the sourced file used.
496
497   + If code would use several functions with similar names,
498     it is RECOMMENDED to create a (well-named) sub-library for them.
499
500   + Code MAY create deep library trees if needed, it SHOULD store
501     common path prefixes into global variables to make sourcing easier.
502
503   + Contributors, look at other files in the subdirectory. You SHOULD
504     improve their filenames when adding-removing other filenames.
505
506   + Library files SHOULD NOT have executable flag set.
507
508   + Library files SHOULD have an extension .sh (or perhaps .bash).
509
510   + It is RECOMMENDED for entry scripts to also have executable flag unset
511     and have .sh extension.
512
513 + Each entry script MUST start with a shebang.
514
515   + "#!/bin/usr/env bash" is RECOMMENDED.
516
517   + Code SHOULD put an empty line after shebang.
518
519   + Library files SHOULD NOT contain a shebang, as "source" is the primary
520     method to include them.
521
522 + Following that, there SHOULD be a block of comment lines with copyright.
523
524   + It is a boilerplate, but human eyes are good at ignoring it.
525
526   + Overhead for git is also negligible.
527
528 + Following that, there MUST be "set -exuo pipefail".
529
530   + It acts as an anchor for humans to start paying attention.
531
532 Then it depends on script type.
533
534 Library documentation
535 `````````````````````
536
537 + Following "set -exuo pipefail" SHALL come the "import part" documentation.
538
539 + Then SHALL be the import code
540   ("source" commands and a bare minimum they need).
541
542 + Then SHALL be the function definitions, and inside:
543
544   + "set -exuo pipefail" again.
545
546   + Following that SHALL be the function documentation explaining API contract.
547     Similar to Robot [Documentation] or Python function-level docstring.
548
549     + See below.
550
551   + Following that SHALL be varius TODOs, FIXMEs and code itself.
552
553     + "Code itself" SHALL include comment lines
554       explaining any non-obvious logic.
555
556     + TODO: Document (in an appropriate place) how TODOs differ from FIXMEs.
557
558   + There SHALL be two empty lines before next function definition.
559
560 More details on function documentation:
561
562 Generally, code SHOULD use comments to explain anything
563 not obvious from the funtion name.
564
565 + Function documentation SHOULD start with short description of function
566   operation or motivation, but only if not obvious from function name.
567
568 + Documentation SHOULD continue with listing any non-obvious side effect:
569
570   + Documentation MUST list all read global variables.
571
572     + Documentation SHOULD include descriptions of semantics
573       of global variable values.
574       It is RECOMMENDED to mention which function is supposed to set them.
575
576     + The "include descriptions" part SHOULD apply to other items as well.
577
578   + Documentation MUST list all global variables set, unset, reset,
579     or otherwise updated.
580
581   + It is RECOMMENDED to list all hardcoded values used in code.
582
583     + Not critical, but can hint at future improvements.
584
585   + Documentation MUST list all files or directories read
586     (so caller can make sure their content is ready).
587
588   + Documentation MUST list all files or directories updated
589     (created, deleted, emptied, otherwise edited).
590
591   + Documentation SHOULD list all functions called (so reader can look them up).
592
593     + Documentation SHOULD mention where are the functions defined,
594       if not in the current file.
595
596   + Documentation SHOULD list all external commands executed.
597
598     + Because their behavior can change "out of bounds", meaning
599       the contributor changing the implementation of the extrenal command
600       can be unaware of this particular function interested in its side effects.
601
602   + Documentation SHOULD explain exit code (coming from
603     the last executed command).
604
605     + Usually, most functions SHOULD be "pass or die",
606       but some callers MAY be interested in nonzero exit codes
607       without using global variables to store them.
608
609     + Remember, "exit 1" ends not only the function, but all scripts
610       in the source chain, so code MUST NOT use it for other purposes.
611
612       + Code SHOULD call "die" function instead. This way the caller can
613         redefine that function, if there is a good reason for not exiting
614         on function failure.
615
616   + TODO: Programs installed, services started, URLs downloaded from, ...
617
618   + TODO: Add more items when you spot them.
619
620   + TODO: Is the current order recommended?
621
622 Entry script documentation
623 ``````````````````````````
624
625 + After "set -exuo pipefail", high-level description SHALL come.
626
627   + Then TODOs and FIXMEs SHALL be placed (if any).
628
629   + Entry scripts are rarely reused, so detailed side effects
630     are OPTIONAL to document.
631
632   + But code SHOULD document the primary side effects.
633
634 + Then SHALL come few commented lines to import the library with "die" function.
635
636 + Then block of "source" commands for sourcing other libraries needed SHALL be.
637
638   + In alphabetical order, any "special" library SHOULD be
639     in the previous block (for "die").
640
641 + Then block os commands processing arguments SHOULD be (if needed).
642
643 + Then SHALL come block of function calls (with parameters as needed).
644
645 Other general recommendations
646 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
647
648 + Code SHOULD NOT not repeat itself, even in documentation:
649
650   + For hardcoded values, a general description SHOULD be written
651     (instead of copying the value), so when someone edits the value
652     in the code, the description still applies.
653
654   + If affected directory name is taken from a global variable,
655     documentation MAY distribute the directory description
656     over the two items.
657
658   + If most of side effects come from an inner call,
659     documentation MAY point the reader to the documentation
660     of the called function (instead of listing all the side effects).
661
662     + TODO: Composite functions can have large effects. Should we require
663       intermediate functions to actively hide them whenever possible?
664
665 + But documentation SHOULD repeat it if the information crosses functions.
666
667   + Item description MUST NOT be skipped just because the reader
668     should have read parent/child documentation already.
669
670   + Frequently it is RECOMMENDED to copy&paste item descriptions
671     between functions.
672
673   + But sometimes it is RECOMMENDED to vary the descriptions. For example:
674
675     + A global variable setter MAY document how does it figure out the value
676       (without caring about what it will be used for by other functions).
677
678     + A global variable reader MAY document how does it use the value
679       (without caring about how has it been figured out by the setter).
680
681 + When possible, Bash code SHOULD be made to look like Python
682   (or Robot Framework). Those are three primary languages CSIT code relies on,
683   so it is nicer for the readers to see similar expressions when possible.
684   Examples:
685
686   + Code MUST use indentation, 1 level is 4 spaces.
687
688   + Code SHOULD use "if" instead of "&&" constructs.
689
690   + For comparisons, code SHOULD use operators such as "!=" (needs "[[").
691
692 + Code MUST NOT use more than 80 characters per line.
693
694   + If long external command invocations are needed,
695     code SHOULD use array variables to shorten them.
696
697   + If long strings (or arrays) are needed, code SHOULD use "+=" operator
698     to grow the value over multiple lines.
699
700   + If "|| die" does not fit with the command, code SHOULD use curly braces:
701
702     + Current line has "|| {",
703
704     + Next line has the die commands (indented one level deeper),
705
706     + Final line closes with "}" at original intent level.
707
708   + TODO: Recommend what to do with other constructs.
709
710     + For example multiple piped commands.
711
712     + No, "eval" is too unsafe to use.