├── README.md
├── chapter
├── 1_general.md
├── 2_architecture.md
├── 3_implementation.md
├── 4_naming.md
├── 5_layout.md
├── 6_documentation.md
├── 8_safety_security.md
└── lang
│ ├── c-guide.md
│ ├── javascript-guide.md
│ └── python-guide.md
└── res
└── img
├── architecture-bad.svg
├── architecture-better.svg
└── tum-ei-esi-header.svg
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # C³: Common Coding Conventions
6 |
7 | > Keep it simple and solid, let the toolchain be smart,
8 | > code correctness is the duty, readability the art.
9 |
10 |
11 | The goal of these conventions is to be concise, universal, and remarkable. It targets emerging code enthusiasts under time pressure and covers 7 topics:
12 |
13 | 1. [**General Clarifications**](#user-content-general-clarifications)
14 | ([Keep Consistency](#user-content-be-consistent-with-the-existent) •
15 | [Break rules](#user-content-break-rules-if-it-enhances-clarity) •
16 | [Improve Code](#user-content-leave-code-cleaner-than-you-found-it) •
17 | [Terms](#user-content-terminology))
18 | 2. [**Architecture**](#user-content-architecture)
19 | ([Low Coupling](#user-content-aim-for-low-coupling-between-classes) •
20 | [Coherent Abstraction](#user-content-aim-for-coherent-abstraction-levels))
21 | 3. [**Implementation**](#user-content-implementation)
22 | ([DRY](#user-content-dont-repeat-yourself-dry) •
23 | [Small Scopes](#user-content-keep-all-scopes-fileclassfunction-small-and-sorted) •
24 | [Express Ideas](#user-content-express-ideas-in-code-use-domain-specific-names) •
25 | [Sort Args](#user-content-sort-arguments-and-limit-them-to-0--4-per-call) •
26 | [Compose](#user-content-do-not-change-the-same-variable-in-steps-but-compose-once-from-parts))
27 | 4. [**Naming**](#user-content-naming)
28 | ([Pick One](#user-content-pick-one-word-for-one-concept) •
29 | [Bools](#user-content-boolean-variablesfunctions-should-have-a-ishascan-prefix) •
30 | [Subprograms](#user-content-naming-subprograms-procedurefunction) •
31 | [Types](#user-content-naming-types-classstructsubtypes) •
32 | [Variables](#user-content-naming-variables) •
33 | [Word Pairs](#user-content-use-word-pairs-opposites-antonyms))
34 | 5. [**Code Layout**](#user-content-code-layout)
35 | 6. [**Documentation**](#user-content-documentation)
36 | ([Comments](#user-content-write-brief-comments-of-high-quality) •
37 | [TODOs](#user-content-use-todo-and-fixme-tags) •
38 | [Readmes](#user-content-write-readme-files) •
39 | [Logging](#user-content-avoid-print-use-a-library-with-log-levels) •
40 | [File Headers](#user-content-write-file-headers-for-header-files) •
41 | [Docstrings](#user-content-use-docstrings-for-public-apis))
42 | 7. [**Languages**](#user-content-languages)
43 | ([Python](chapter/lang/python-guide.md) •
44 | [C](chapter/lang/c-guide.md) •
45 | [JavaScript](chapter/lang/javascript-guide.md))
46 |
47 |
48 |
49 | To follow this guide, you should already have heard about [Object Oriented Programming](https://www.educative.io/blog/object-oriented-programming) and know basic programming rules, such as writing loops and meaningful functions instead of copy pasting instructions.
50 |
51 |
52 |
53 |
54 |
55 | ## [General Clarifications](#user-content-general-clarifications)
56 |
57 | ### Be consistent with the existent.
58 |
59 | “Consistency with this guide is important. Consistency within a project
60 | is more important. Consistency within one module or function is the most
61 | important” [[PEP8]](#user-content-references).
62 |
63 |
64 |
65 | ### Break rules if it enhances clarity.
66 |
67 | Do not blindly follow this guide but think for yourself. The goal of
68 | software development is keeping the code complexity low. Period. None of
69 | the rules and fancy patterns matters if the code becomes impossible to maintain.
70 |
71 |
72 |
73 | ### Leave code cleaner than you found it.
74 |
75 | We all have seen bad code, we all have written bad code. Code tends to get messy over time.
76 | Therefore, do not only complain about bad code but improve it if you know how. If *you* don't care to do it, why should anyone else?
77 |
78 |
79 |
80 | ### Terminology
81 |
82 | To be universal, we group several concepts under these broad
83 | identifiers:
84 |
85 |
86 | * **Scope** = {Module, File, Namespace, Subprogram}
87 | * **Subprogram** = {Procedure, Function, Method}
88 | * **Type** = {Primitive, Collection, Struct, Class, ...}
89 | * **Collection** = {Array, List, Tuple, Dict, Map, ...}
90 |
91 |
92 |
93 |
94 |
95 |
96 | ## [Architecture](#user-content-architecture)
97 |
98 | To manage complexity, divide your software into smaller parts (scopes)
99 | such as modules, classes, and subprograms. Where to separate and where
100 | to connect scopes is the art of good architecture.
101 |
102 | Two common mistakes in architecture design are the creation of a monster class that has too many responsibilities and letting each class communicate with too many other classes:
103 |
104 | 
105 |
106 |
107 | Instead, limit the amount and direction of information exchange between classes and create larger architectures from the following building blocks:
108 |
109 | 
110 |
111 |
112 |
113 | ### Aim for low coupling between classes.
114 |
115 | You may have many classes but each class should communicate with as few
116 | others as possible. If any two classes communicate at all, they should
117 | exchange as little information as possible.
118 |
119 |
120 |
121 | ### Aim for coherent abstraction levels.
122 |
123 | Each scope should reflect a single coherent level of abstraction that
124 | corresponds to its hierarchy level [[ClCd]](#user-content-references). In your UML, abstraction should
125 | decrease from top to bottom. In your code, the deeper you are in a call
126 | tree, the more specific your instructions can be. Avoid state variables
127 | at high abstraction levels.
128 |
129 |
130 |
159 |
160 | > ⚠ **Caution:** *Mixing abstraction levels creates confusion and introduces unnecessary dependencies.*
161 |
162 |
163 | [Read more ...](chapter/2_architecture.md)
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | ## [Implementation](#user-content-implementation)
172 |
173 | Once you have an initial plan for the architecture, you can start
174 | writing the code for classes and subprograms.
175 |
176 |
177 |
178 | ### Don't Repeat Yourself (DRY).
179 |
180 | Any piece of data or logic should have a single source.
181 | Duplicated code is difficult to maintain and represents a missed opportunity for abstraction.
182 | As a rule of thumb: If you repeat more than 2 statements more than 2 times, write a new
183 | subprogram. At best, any atomic change in program logic should only
184 | affect a single line of code.
185 |
186 | There are two code smells that should remind you of this rule:
187 |
188 | * **Copy & Paste:** Every time you take your mouse and mark lines with the intention to copy them, you are going to violate this rule. Instead of slightly adjusting copied lines, think about the common pattern between those lines and create a new function.
189 |
190 | * **Repeated `if-else` and `switch-case` statements:** If you are testing the same conditions at different locations (e.g. state variables), you can abstract these differences with Polymorphism and the [Strategy Pattern](https://refactoring.guru/design-patterns/strategy).
191 |
192 |
193 |
194 | ### Keep all scopes (file/class/function) small and sorted.
195 |
196 | Define subprograms and variables in the smallest scope possible and limit
197 | their exposure to external code. Put declarations at the beginning
198 | of each scope and initialize variables directly at the declaration. Do
199 | not reuse variables in nested scopes or for different purposes.
200 |
201 |
202 |
203 | ### Express ideas in code: use domain-specific names.
204 |
205 | Avoid magic numbers (literal numbers with unclear origin/purpose)
206 | but always create constants with meaningful names.
207 | Create new types or derive subtypes from primitives to create more
208 | specific names, especially for physical quantities.
209 |
210 |
211 | **Bad ❌**
212 | ```c
213 | double limit = 13.89; // unit not clear
214 | from_to(int x, int y,
215 | int x2, int y2); // vague argument names
216 |
217 | if (speed > limit &&
218 | t.h > 22 && t.h < 6){ ... } // 22 and 6 are magic numbers
219 | ```
220 |
221 | **Better ✔**
222 | ```c
223 | MeterPerSecond limit = SPEED_LIMIT_NIGHT;
224 | drive(Point origin, Point destination);
225 |
226 | isNight = (T_NIGHT_MIN < t.h && t.h < T_NIGHT_MAX);
227 | isSpeeding = (limit < speed);
228 | if (isSpeeding && isNight){ ... }
229 | ```
230 |
231 |
232 |
233 | ### Sort arguments and limit them to 0 – 4 per call.
234 |
235 | If the argument list of a subprogram grows too long, try to combine related arguments in a
236 | new data structure. For example, instead of passing `x`, `y`, `z`
237 | coordinates individually, use a single vector.
238 |
239 |
240 |
256 |
257 |
258 |
259 |
260 | ### Do not change the same variable in steps but compose once from parts.
261 |
262 | Within a subprogram, do not modify the same variable in several steps,
263 | e.g. by summing up an amount using `total += ...` multiple times.
264 | Instead, call functions that return some part of the final value and
265 | then compose the final value of these parts in one instruction at the
266 | end. E.g. `total = partA + partB`.
267 |
268 |
269 |
270 |
Bad ❌
Better ✔
271 |
272 |
273 |
274 | ```c
275 | totalIncome = 0
276 | // ... long code to get contract
277 | totalIncome += contract.salary
278 | // ... long code to access taxoffice
279 | totalIncome -= taxoffice[id].tax
280 | ```
281 |
282 |
293 |
294 |
295 | [Read more ...](chapter/3_implementation.md)
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 | ## [Naming](#user-content-naming)
304 |
305 | Code should communicate behavior to other humans with lower complexity than the behavior it inherits. Since code mostly consists of custom names, your ability to abstract concepts with meaningful names is most important for readability.
306 |
307 |
308 |
309 | ### Pick one word for one concept.
310 |
311 | Each concept should be described by a single word. Do not use `send()`, `write()`, and `transmit()` as synonyms for the same process, such as sending a message over a bus. Same holds true for `handleRequest()`, `processQuery()`, or `manageIncomingPacket()`.
312 |
313 | Each word should only describe a single concept. Do not use `activate()` for setting a boolean variable and sending an activation packet to another system component. The first procedure is safe and instant, the second could fail, block execution, or run asynchronously. Better call it `sendActivationMsg()`.
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 | ### Boolean Variables/Functions should have a `is/has/can` prefix.
322 | Clean code reads like prose and these prefixes achieve clear and concise naming.
323 | There is no difference between the naming of variables, e.g. `hasElements`, and functions, e.g. `hasElements()`, except that functions can also answer true/false questions regarding arguments, such as `isFile(path)` or `user.hasAccessTo(file)`.
324 |
325 |
327 |
328 | * consider the slightly uncommon prefixes `can` to express abilities/possibilities, e.g. `canWalk`.
329 | * boolean names regarding [Collections](https://en.wikipedia.org/wiki/Collection_(abstract_data_type)) should use `Each/Any` before the prefix, e.g. `isEachLightOn` / `isAnyLightOn`
330 | * prefer positive forms. Use `isActive` not `isInactive` to avoid confusing negations (`!isInactive`). Same for `hasElements` (not `isEmpty`) and `isEnabled` (not `isDisabled`).
331 | * Avoid further uncommon prefixes, such as `does`, `are`, `was`, `will`, `should`.
332 |
333 |
334 | | Rule | Bad ❌ | Better ✔ |
335 | |:---------------|:--------------------------------------------------|:------------|
336 | | Consider `can` | `isAllowedToWalk`, `hasWalkAbility`, `isWalkable` | `canWalk` |
337 | | Avoid `not` | `isNotEmpty`, `!isEmpty` | `hasElements` |
338 | | Avoid `are`: | `areAllLightsOn`, `isAllLightsOn` , `allLightsOn` | `isEachLightOn` |
339 | | Avoid `was/had`| `wasSend`, `hasBeenSent`, `hadArrived` | `isSent` |
340 | | Avoid `does` | `doesUseIO`, `mightUseIO` | `isUsingIO`, `canUseIO` |
341 |
342 |
343 | Fun fact: The old [jQuery 1.7](https://code.jquery.com/jquery-1.7.2.js) had a boolean called `doesNotAddBorder`. Now they use `isBorderBox`.
344 |
345 |
346 |
347 | ### Naming Subprograms (=Procedure/Function)
348 |
349 | Procedures *may* return values, functions always return a value. Methods are subprograms of a class.
350 | * procedure names should start with a verb. e.g. `syncViews()`, `list.addItem(x)`.
351 | * function names should describe the result and, if suitable, its type. e.g. `time_ms(), sin(x), isFile(path)`
352 | * class methods should not repeat or include the name of the class. Define `Line.length()`, not `Line.getLineLength()`
353 |
354 | > ⚠ **Caution:** *Single noun subprograms should be pure functions! Never let e.g. `x.length()` change a state.*
355 |
356 |
357 |
358 | ### Naming Types (=Class/Struct/Subtypes)
359 |
360 | * type names should be capitalized nouns. E.g. `Integer`, `Date`, `Line2D`
361 | * enums/structs are types and should be named as types without a special prefix/suffix.
362 | E.g. `enum Color = {RED, GREEN, BLUE}`
363 | * interface names can start with a capital `I` and can also be adjectives. E.g. `IObservable`
364 |
365 |
366 |
367 | ### Naming Variables
368 |
369 | * variables with a large scope *should* have long names, variables with a small scope *may* have short names [[CdCm]](#user-content-references).
370 | * collections (set, array, dict) should have a plural name. E.g. `cars`, `indices`
371 | * the prefix `n` or `num` should be used for names representing the total number of objects in a collection. E.g. `numCars`
372 | * write constant names in capitals. E.g `CFG_TEMPERATURE_MAX = 80.0`
373 | * prefix global variables with `g_`
374 |
375 |
376 |
377 |
Bad ❌
Better ✔
378 |
379 |
380 |
381 | ```python
382 | score_list = [0] * scores
383 | for idx, val in score_list:
384 | score_list = val + 1
385 | ```
386 |
387 |
396 |
397 |
398 |
399 | ### Use word pairs (opposites, antonyms).
400 |
401 | If you `start` something, you should `stop` it and not `end` it [[CdCm]](#user-content-references).
402 | While most opposites can be created by using `un-` or `de-` prefixes (`lock/unlock`), some are more distinct and allow code alignment:
403 |
404 | Verb pairs with same length:
405 |
406 | | `set` |`send` |`query` |`insert` |`attach` |`show` |`split` |`enter` |`accept` |
407 | |-------|-------|--------|---------|---------|-------|--------|--------|----------|
408 | | `get` |`recv` |`reply` |`delete` |`detach` |`hide` |`merge` |`leave` |`reject` |
409 |
410 |
411 |
412 | 👆 List of further word pairs
413 |
414 | Verb pairs that differ by one character are more visually distinct but still easy to align with one extra space:
415 |
416 | | `open` | `read` | `load` | `push` | `start` | `create` | `grant` | `hit` | `prepend` | `empty` |
417 | |----------|---------|---------|--------|---------|-----------|---------|--------|-----------|----------|
418 | | `close` | `write` | `store` | `pop` | `stop` | `destroy` | `deny` | `miss` | `append` | `full` |
419 |
420 |
421 | Noun and adjective pairs with same/similar length:
422 |
423 | | `max` |`next` |`head` |`new` |`row` |`ack` |`front` |`source` |`client` |`primary` |`leader` |
424 | |-------|-------|-------|------|------|------|--------|---------|---------|----------|-----------|
425 | | `min` |`prev` |`tail` |`old` |`col` |`nak` |`rear` |`target` |`server` |`replica` |`follower` |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 | > ⚠ **Avoid inappropriate terms:** Many organizations discourage the use of `master/slave` due to their negative association in different cultures. See [1](https://www.drupal.org/node/2275877) and [2](https://bugs.python.org/issue34605).
435 | > ⚠ **Avoid useless noise-terms:** E.g. `data`, `info`, `process`. What would be the difference between `Product`, `ProductData`, and `ProductInfo`?
436 |
437 |
438 |
439 | [Read more ...](chapter/4_naming.md)
440 |
441 |
442 |
443 |
444 |
445 |
446 | ## [Code Layout](#user-content-code-layout)
447 |
448 | A clear and consistent visual appearance of your code improves readability and readability helps to understand the code.
449 |
450 | * Existing Project: [Stick to the existing](#user-content-be-consistent-with-the-existent) recommendations and tools.
451 | * New Project: Use an automatic code formatter. Examples:
452 |
453 | | Language | Tool |
454 | |:-----------|--------|
455 | | Python | [black](https://pypi.org/project/black/) |
456 | | C | [uncrustify](http://uncrustify.sourceforge.net/) |
457 | | C++ | [clang-format](http://clang.llvm.org/docs/ClangFormat.html) |
458 | | JavaScript | [prettier.io](https://prettier.io/) |
459 |
460 |
461 |
462 | 👆 Read more ...
463 |
464 | Here are some example recommendations that would be ensured by most formatters:
465 | * aim for one statement and less than 80 characters per line
466 | * indent with spaces not tabs because editors do not agree on tab width
467 | * surround top-level function and class definitions with two or three blank lines.
468 | * surround binary operators (=, ==, +) with a single space, except when nested inline
469 | * break lines before operators and align operators vertically
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 | ## [Documentation](#user-content-documentation)
479 |
480 | English is the language of programming, so documentation should also be in English.
481 |
482 |
483 |
484 | ### Write few brief comments of high quality.
485 |
486 | Choose your words carefully and comment only what the code cannot say, that is *why* you did it, maybe *what* you did, but never *how*.
487 | Change comments when code changes because “comments that contradict the code are worse than no comments” [[PEP8]](#user-content-references).
488 |
489 |
490 |
491 |
Bad ❌
Better ✔
492 |
493 |
494 |
495 | ```python
496 | if t.h > NIGHT_H: # Check if night
497 | if ifr.sense(): # detect person
498 | turnLightOn() # set Pin 13
499 | lockLight(TIMEOUT) # TIMEOUT=5s
500 | ```
501 |
502 |
511 |
512 |
513 | Further Don'ts:
514 |
515 | * Don't commit commented-out code. Just remove.
516 | * Don't create headings with `S E P A R A T E D` letters because you cannot search for them.
517 | * Don't assume insider knowledge but write simple comments for anybody on the planet.
518 | * Don't make jokes or use cute language.
519 | * Don't comment closing braces. They just indicate that your blocks are too long.
520 |
521 |
522 |
523 | ### Use `TODO` and `FIXME` tags.
524 |
525 | Comment unfinished work with `TODO:` or `FIXME:`, which allows to search & find these lines later. Some IDEs will automatically highlight these tags via [extensions](https://open-vsx.org/extension/wayou/vscode-todo-highlight).
526 | A `TODO` is more urgent and needs to be done, a `FIXME` would be nice to have but is not required.
527 |
528 |
529 |
530 | ### Write Readme files.
531 |
532 | There are two different interest groups for your code, so please make sure that your Readme addresses both.
533 |
534 | * **Users:** How to install and run your code with examples. Supported OS. Release versions and change logs.
535 | * **Developers:** How to compile. Module structure, dependencies, contribution rules, where to contact developers.
536 |
537 |
538 | ### Avoid `print`. Use a library with log levels.
539 |
540 |
541 | | Level | Use-case | Example |
542 | |:----------|-----------------------------------------------|----------------|
543 | | Fatal: | the system cannot continue operation | segfault |
544 | | Error: | some function is (currently) not working | no connection |
545 | | Warn: | unexpected event but retry/alternative works | dropped packet |
546 | | Notice: | notable events that do not happen often | new device |
547 | | Info: | usual business events relevant to the user | user connected |
548 | | Debug: | technological info relevant for developers | protocol stages|
549 | | Trace: | step-by-step implementation details | loop index |
550 |
551 |
552 |
553 | * Each log entry should at least output log level and file/module name (or topic label). Timestamps and line numbers are optional.
554 | * Log with context and avoid messages like “Operation Failed” or “Write Complete”.
555 | * Separate message (`"User connected"`) from parameters (`"ip=%s", ip`)
556 |
557 |
558 | Bad ❌
559 | ```python
560 | print("User %s connected from %s", uid, ip)
561 | ```
562 | Better ✔
563 | ```python
564 | log.info("P2P: User connected. [id=%s, ip=%s]", uid, ip)
565 | ```
566 |
567 |
568 |
569 |
570 |
571 | ### Write file headers for header files.
572 |
573 | Each code file with interfaces (e.g. `.h` files in C) should start with a block comment that briefly explains what this module/class/lib does. However, do not provide author name or changelogs as this info belongs into the [Version Control System](https://www.geeksforgeeks.org/version-control-systems/).
574 |
575 |
576 |
577 | ### Use Docstrings for public APIs
578 |
579 | Docstrings are specially formatted comments that can be converted into a code documentation. This is useful as soon as other people start to depend on your interfaces.
580 |
581 |
582 |
583 | 👆 Docstring Example
584 |
585 | ```c
586 | /**
587 | * Solves equations of the form a * x = b
588 | * @example
589 | * // returns 2
590 | * globalNS.method(5, 10);
591 | * @example
592 | * // returns 3
593 | * globalNS.method(5, 15);
594 | * @returns {Number} Returns the value of x for the equation.
595 | */
596 | globalNS.method = function (a, b) {
597 | return b / a;
598 | };
599 | ```
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 | ## [Languages](chapter/6_languages.md)
609 |
610 | Each programming language has special mechanisms and some rules are only applicable to a certain language. We also try to give an overview of language-specific rules, but the following list is unfinished and work in progress.
611 |
612 |
613 | * **[Python](chapter/lang/python-guide.md)**
614 | * **[C](chapter/lang/c-guide.md)**
615 | * **[JavaScript](chapter/lang/javascript-guide.md)**
616 |
617 |
618 |
619 |
620 |
621 |
622 | ## References
623 |
624 | This guide is partly based on the principles that are explained in the following books and documents and we can recommend them as further reading material.
625 |
626 |
627 |
628 | #### General Design Principles
629 |
630 | Students from TUM and other universities can read these books for free. Simply click the links below and login with your university credentials.
631 |
632 | * [CdCm] S. McConnell: [“Code Complete”](https://learning.oreilly.com/library/view/code-complete-second/0735619670/?ar), Pearson Education, 2004.
633 | * [ClCd] R. C. Martin: [“Clean Code: A Handbook of Agile Software Craftsmanship”](https://learning.oreilly.com/library/view/clean-code-a/9780136083238/?ar), Pearson Education, 2009.
634 | * [ClAr] R. C. Martin: [“Clean Architecture: Guide to Software Structure and Design”](https://learning.oreilly.com/library/view/clean-architecture-a/9780134494272/?ar), Pearson Education, 2017.
635 | * [HdFi] E. Freeman et al.: [“Head First Design Patterns”](https://learning.oreilly.com/library/view/head-first-design/9781492077992/?ar), 2nd Edition, O’Reilly Media, 2020.
636 |
637 |
638 |
639 | #### Language Specific Coding Conventions
640 |
641 | * [PEP8] G. Van Rossum, B. Warsaw, and N. Coghlan: [“PEP 8: Style Guide for Python Code”](https://www.python.org/dev/peps/pep-0008/), Python.org, 2001.
642 | * [MISRA-C] Motor Industry Software Reliability Association: “Guidelines for the use of the C language in critical systems.”, 2004
643 | * [MISRA-C++] Motor Industry Software Reliability Association: “Guidelines for the use of the C++ language in critical systems.”, 2008
644 | * [JPL-C] [JPL Institutional Coding Standard for the C Programming Language](https://yurichev.com/mirrors/C/JPL_Coding_Standard_C.pdf)
645 | * [C++ coding style (JSF+MISRA)](http://micro-os-plus.github.io/develop/coding-style/):
646 | * [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)
647 | * [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html)
648 |
649 |
650 | #### Videos
651 | * [Clean Code - Uncle Bob](https://www.youtube.com/watch?v=7EmboKQH8lM)
652 |
--------------------------------------------------------------------------------
/chapter/1_general.md:
--------------------------------------------------------------------------------
1 | ## Additional Clarifications
2 |
3 |
4 | ### Apply OOP
5 |
6 | One method to maintain complexity is abstraction and encapsulation using
7 | classes and interfaces. Although, not every part of your software design
8 | fits well into an object, humans can easily understand objects with
9 | attributes and methods and their relations to each other.
10 |
11 |
12 | * **Encapsulation:** Group related attributes and methods.
13 | * **Abstraction:** Provide high-level interfaces, hide details.
14 | * **Inheritance:** Derive classes from other classes (hierarchy).
15 | * **Polymorphism:** Overwrite derived methods to change behavior.
16 |
17 |
18 |
19 | ### Use Unified Modeling Language (UML)
20 | UML is great when trying to plan or explain architecture and code structure.
21 | Possible UML relations between objects:
22 |
23 |
24 | | **Relation** | **Description** (P: parent, C: child) | **Example P** | rel.| **Example C** |
25 | | --------------|:------------------------------------------|---------:|:--------:|:--------------|
26 | | Association: | "P may use a C. C may belong to P" | Human | –––––– | Computer |
27 | | Dependency: | "P depends on C. C provides for P" | Human | - - - -> | Food |
28 | | Aggregation: | "Group P has a C. C is assigned to P" | Company | ◇––––– | Human |
29 | | Composition: | "P is made of C. C is part of every P" | Human | ◆––––– | Leg |
30 | | Realization: | "P abstracts C. C implements P." | Human | ◁- - - - | Socrates |
31 | | Inheritance: | "P is the class of C. Every C *is a* P." | Mammal | ◁––––– | Human |
32 |
33 |
34 | > :warning: **Aggregation vs. Composition:** If you remove the composition you will also
35 | > remove the children, but if you remove the aggregate the children still
36 | > exist. Remove the company and you still have humans, remove the human
37 | > and you also remove his/her legs.
38 |
39 |
--------------------------------------------------------------------------------
/chapter/2_architecture.md:
--------------------------------------------------------------------------------
1 |
2 | ## Additional Architecture Rules
3 |
4 | [Read base rules.](../README.md#user-content-architecture)
5 |
6 |
7 | ### Be open for extension, but closed for modification.
8 |
9 | If you need to add a new feature (logic), the architecture should only
10 | be extended with no or little modification. How? Separate class methods
11 | that could have several behaviors and encapsulate them behind a new
12 | interface. Creating multiple, specific interfaces is better than one
13 | giant, general-purpose interface that needs to change. Ask yourself: If
14 | you add a new class (e.g. new feature) to your design, how many classes
15 | have to change?
16 |
17 |
18 | ### Separate models from views and control (MVC).
19 |
20 | A model (program logic+states) is the heart of each module and
21 | operations on the open heart are dangerous. Therefore, larger modules
22 | should protect the model from
23 |
24 | * direct input by having a controller that preprocesses requests
25 | * direct output by having one or more views that provide different output formats
26 |
27 | External modules can access the controller (if they want to change the
28 | model's state) or access the views (if they want to know the model's
29 | state). See
30 | [MVC](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller).
31 |
32 |
33 | ### Depend on abstractions, not implementations
34 |
35 | Abstract superclasses and interfaces allow you to hide implementation
36 | details, which reduces dependencies. In UML, associations between
37 | semantically different objects should preferably point to interfaces,
38 | instead of concrete classes. In code, statements such as `include` or
39 | `import` should mostly bring interfaces and abstract classes into the
40 | scope. E.g. instead of calling `display3.setLED(2, red)` directly, use
41 | an abstract `GUI.warnUser()`. If you depend on concrete classes, make
42 | sure they are small, singletons, closely related, or really stable (e.g.
43 | `String` in Java).
--------------------------------------------------------------------------------
/chapter/3_implementation.md:
--------------------------------------------------------------------------------
1 | ## Additional Implementation Rules
2 |
3 | [Read base rules.](../README.md#user-content-implementation)
4 |
5 |
6 |
7 | ### Prefer early (compile-time) checking over late (run-time) checking
8 |
9 | If possible, use all of the following mechanisms:
10 | 1. See the compiler as your friend and care for its warnings. The goal is not to write code that compiles but code that is correct (and readable).
11 | 2. Use a linter. A linter will check your code while you type and provides the earliest feedback.
12 | 3. Use static typing with many individual types to detect type mismatches early.
13 | 4. Use static asserts to detect unintended changes to your code.
14 | 5. Use exceptions with meaningful trace-output as your last line of defense. Consider any OS-Error(e.g. `segfault`) or direct microcontroller-reset as the worst-case and as an indication that your workflow – not only your code – is flawed.
15 |
16 |
17 |
18 | ### Code simple, not smart (KISS) and only what you need (YAGNI)
19 |
20 | Keep it simple and stupid (KISS): Write straightforward code to achieve
21 | your goal. If you use a compiler, do not try to outsmart it. Compilers
22 | are really sophisticated and can optimize simple code much better than
23 | you.
24 |
25 | You Ain't Gonna Need It (YAGNI): Don't code out every little detail that
26 | you can possibly think of. Instead, implement only what is absolutely
27 | necessary but be open for extensions.
28 |
29 |
30 | ### Structure Files into 1. Imports, 2. Constants, 3. Publics, 4. Privates
31 |
32 | Structure each code file into parts: 1. imports/includes, 2. global constants, 3.
33 | public classes/functions, 4. private classes/functions, and optional 5. direct
34 | instructions in the `main` file. Keep these parts in order and
35 | separated, e.g. do not include files or define globals within a function
36 | declaration. Provide comment headings for these parts such that it easy
37 | to identify them when scrolling through the file.
38 |
39 |
40 | ### Subprograms should either handle states or calculate results
41 |
42 | Most languages do not distinguish between procedures and functions but
43 | it is useful. Procedures modify states and may return a value. Pure
44 | functions are stateless and always return a value (or throw an exception
45 | otherwise). At best, a function should only work with the input
46 | variables to make clear on which data it depends. If your subprogram
47 | does change a state and returns a result, make sure to name it as a
48 | procedure (see [3.1](#name:subs){reference-type="ref"
49 | reference="name:subs"}).
50 |
51 |
52 | ### Sort conditions (<) and cases (expected first)
53 |
54 | Conditional statements should be written in the form `(3 < x)` instead
55 | of `(x > 3)` even if you think "x larger 3". For most cultures, numbers
56 | increase from left to right and thus it is easier to understand,
57 | especially when you add an upper bound: `(3 < x) && (x < 7)`. Handle the
58 | nominal or expected case first and avoid negations, e.g. use
59 | `if hasElement()` instead of `if not isEmpty()`.
60 |
61 |
62 | ### Return often and soon, if errors ascend, but valid result, just once at the end.
63 |
64 | If an input is invalid or if any other error occurs, immediately return
65 | to avoid unnecessary code execution and nested errors. However, valid
66 | results should be returned only at the very end of a function body. By
67 | having a single success exit, it is easier to verify data validity.
68 | Furthermore, fail immediately and loudly. For any severe exception, your
69 | program should immediately crash and output the cause.
70 |
71 |
72 |
73 | ### Use what you define and avoid unreachable/dead code.
74 |
75 | There should be no unused declarations of variables, arguments,
76 | functions, or classes. Furthermore, avoid *unreachable code* (e.g. after
77 | `return`) and *dead code*, which has no effect (e.g. is redundant).
78 |
--------------------------------------------------------------------------------
/chapter/4_naming.md:
--------------------------------------------------------------------------------
1 | ## Additional Naming Suggestions
2 |
3 | [Read base rules.](../README.md#user-content-naming)
4 |
5 |
6 |
7 | ### Class Name Suffixes
8 |
9 | Class names often have a suffix term that indicates the purpose (and not only the topic) of that class. While there seems to be no common agreement on the notation, we find the following distinction useful:
10 |
11 | * `Factory`/`Builder`: creates objects and transfers ownership (e.g. to a Manager).
12 | * `Manager`: stateless, owns and provides access to same-type objects (e.g. `SensorManager`).
13 | * `Controller`: stateful, handles communication between different objects (e.g. `FlightController`).
14 | * `Handler`: waits for and processes a single-type object, without owning it (e.g. `EventHandler`).
15 |
16 |
17 |
18 | ### High-level Scopes (= Module/Package/Namespace)
19 |
20 | The names for packages or namespaces, which should prevent name clashes, should be short as they are used often within the code. In this case, choosing an abbreviation or acronym makes sense.
21 |
22 |
23 |
24 | ### Use physical units as type names.
25 |
26 | In embedded systems, you often have to deal with physical quantities. To make clear which unit a certain variable has, you should define your own (sub)types for physical units based on numerical type, such as `Meter` and `Second` from `Float`, and then declare variables as `Meter safety_distance = 5.0;`.
27 |
28 |
29 |
30 | ### Use abbreviations cautiously and only common ones.
31 |
32 | To abbr. or not to abbreviate? Truth is, neither `GetTheLatestWebSiteAccessTimeInMilliseconds()`, nor `pm_rcv_bat_stat()` are reader friendly.
33 | Use abbreviations only for small scopes, function arguments, or in combination with full names (`move_cmd`).
34 | Avoid abbreviations if they only save one character (`usr`), are too cryptic (`cmp`), or can be confused with other terms (`tmp`). If you use them, stick to the following common abbreviations (already a lot):
35 |
36 |
37 | 👆 List of common coding abbreviations
38 |
39 |
40 | | **Abbr.** | **Meaning** | | **Abbr.** | **Meaning** |
41 | |--------|-----------------|---|--------|------------|
42 | | `arg` | argument | | `mid` | middle |
43 | | `app` | application | | `min` | minimum |
44 | | `auth` | authentication | | `mem` | memory |
45 | | `avg` | average | | `mon` | monitor |
46 | | `bat` | battery | | `msg` | message |
47 | | `buf` | buffer | | `net` | network |
48 | | `cb` | callback | | `num` | number |
49 | | `cfg` | config. | | `obj` | object |
50 | | `clk` | clock | | `pkg` | package |
51 | | `col` | column | | `pkt` | packet |
52 | | `cnt` | counter | | `pos` | position |
53 | | `cmd` | command | | `pt` | point |
54 | | `ctx` | context | | `ptr` | pointer |
55 | | `dev` | device | | `pwr` | power |
56 | | `doc` | document | | `px` | pixel |
57 | | `drv` | driver | | `rnd` | round |
58 | | `dt` | delta time | | `reg` | register |
59 | | `el` | element | | `rot` | rotation |
60 | | `env` | environment | | `sep` | separator |
61 | | `err` | error | | `std` | standard |
62 | | `exc` | exception | | `str` | string |
63 | | `fh` | file handler | | `sys` | system |
64 | | `fmt` | format | | `tmr` | timer |
65 | | `hdr` | header | | `ts` | timestamp |
66 | | `hex` | hexadecimal | | `val` | value |
67 | | `img` | image | | `var` | variable |
68 | | `idx` | index | | `win` | window |
69 | | `len` | length |
70 | | `lib` | library |
71 | | `lvl` | level |
72 | | `max` | maximum |
73 |
74 |
75 | Per-second/minute acronyms: `fps` (frame), `rpm` (rotations), `mps` (meter)
76 | Avoid these abbr.: `tmp`, `fun`, `chk`, `dis`, `usr`, `cpy`, `tgl`, `txt`, `pc`, `mov`, `sec`
77 |
78 |
79 |
80 |
81 |
82 | 👆 List of Domain Specific Abbreviations
83 |
84 | ### Abbreviations and Acronyms in Embedded Systems:
85 |
86 | * Sensors: `IMU` (=`ACC`, `GYR`, `MAG`), `BARO`, `TEMP`, `GPS` (= `lat`, `lon`, `alt`)
87 | * Buses: `USB`, `CAN`, `SPI`, `I2C`, `UART`, `ETH`, `PCI`
88 | * Processor: `CPU`, `GPU`, `MCU`: `RAM`, `ROM`, `ISR`, `ADC`, `DAC`, `RTC`, `CLK`, `DMA`
89 | * Software: `API`, `CLI`, `GUI`, `HAL`, `OS`, `VM`, `PID`, `UID`, `LSB`, `MSB`, `CRC`
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/chapter/5_layout.md:
--------------------------------------------------------------------------------
1 | ## Code Layout (Visual Appearance)
2 | A clear and consistent visual appearance of your code improves readability and readability helps to understand the code.
3 |
4 | * Existing Project: Stick to the existing recommendation and tools.
5 | * New Project: Use an automatic code layouter. Examples:
6 |
7 |
8 | | Language | Tool |
9 | |:-----------|-------------------------------------------------------------|
10 | | C | [uncrustify](http://uncrustify.sourceforge.net/) |
11 | | C++ | [clang-format](http://clang.llvm.org/docs/ClangFormat.html) |
12 | | Python | [black](https://pypi.org/project/black/) |
13 | | JavaScript | [prettier.io](https://prettier.io/) |
14 |
15 |
16 | Here are some example recommendations that would be ensured by most layouters:
17 |
18 | * aim for one statement and less than 80 characters per line
19 | * indent with spaces not tabs because editors do not agree on tab width
20 | * surround top-level function and class definitions with two or three blank lines.
21 | * surround binary operators (=, ==, +) with a single space, except when nested inline
22 | * break lines before operators and align operators vertically
23 |
24 |
--------------------------------------------------------------------------------
/chapter/6_documentation.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/chapter/8_safety_security.md:
--------------------------------------------------------------------------------
1 | ## Safety and Security
2 |
3 | Both topics are very complex and thus cannot and shall not be covered in detail in this guide.
4 | However, they are important, so you should have a basic understanding of how this affects your code.
5 |
6 | **Safety** is in general achieved by
7 |
8 | * limiting certain language constructs,
9 | * testing and static analysis,
10 | * inspection and validation by other people.
11 |
12 | **Security** is achieved by
13 |
14 | * using cryptography such as encryption, signatures, and hashes
15 | * careful management of the involved keys (where/how to store)
16 | * relying on well-established libraries and never implementing own crypto
17 |
18 |
19 |
20 | ### Safety Rules
21 |
22 | #### Validate any external input.
23 |
24 | Do not make any assumption about input variables that you do not have control of. This means that you should perform range checks before further processing variable. E.g. if your function requires a length argument, check that is a positive value and smaller than the largest value your function can handle.
25 |
26 | ```python
27 | if 0 <= x.len <= LEN_MAX: raise ValueError
28 | ```
29 |
30 |
31 |
32 | #### All loops must have fixed bounds.
33 |
34 | Instead of a simple `while(cond)` loop, provide a fixed number of retries, e.g. `while(cond && retries < 5)`. This will prevent that your program gets stuck in an infinite loop.
35 |
36 |
37 |
38 | #### Check the return value of all non-void functions.
39 |
40 | Never assume that functions will return successfully because they do so most of the time.
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/chapter/lang/c-guide.md:
--------------------------------------------------------------------------------
1 | ### C Specific Advice
2 |
3 | #### Object Oriented Programming in C
4 |
5 | C does not support real OOP but the following rules can help to transfer some ideas of OOP to C.
6 |
7 | * **Think of a file as a class:** Functions that appear in the header file are public, while functions that only appear in the `.c` files are private.
8 |
9 | * **Create namespaces:** use a capital prefix before each “public” function name to indicate their belonging to a certain source file. For example, in `led.c` use `LED_switchOn( redLed );` instead of `switchOn(redLed)`
10 |
11 | * **Use structs to encapsulate attributes:** Instead of individual variables, group variables that would belong to a class in a struct. You can then pass a reference of this struct as the first argument to a function.
12 |
13 |
14 | #### Further
15 |
16 | * **Constants**: for constants prefer `const` over preprocessor `#define`
17 | * **Booleans**: Use `bool` from `stdbool.h` whenever you have a boolean value
18 | * **Sizeof**: use `sizeof` on the variable; not the type
19 |
--------------------------------------------------------------------------------
/chapter/lang/javascript-guide.md:
--------------------------------------------------------------------------------
1 | ### JavaScript Specific Advice
2 |
3 |
4 | #### Creating Namespaces
5 |
6 | Functions that do not belong to a class should still be encapsulated into namespaces.
7 |
8 | ```javascript
9 | const car = {
10 | start: () => { console.log('start'); },
11 | stop: () => { console.log('stop'); },
12 | }
13 | ```
14 |
15 |
16 |
17 | #### Naming Pitfalls
18 |
19 | * Never use `e` as variable name, it is too ambiguous. For local short names use
20 | * `el` for elements
21 | * `ev` for events
22 | * `ex` for exceptions
23 | * `err` for error
24 |
25 |
26 | #### Event Handling
27 |
28 | * Use `el.addEventHandler('mousedown', fun)` instead of assigning `el.onmousedown = fun`.
29 |
30 |
31 |
32 | #### Performance
33 |
34 | While you should not optimize while writing the initial code, JavaScript is often the bottleneck in web applications.
35 |
36 |
37 | * **Reduce the complexity of your selectors.** Selector complexity can take more than 50% of the time needed to calculate the styles for an element, compared to the rest of the work which is constructing the style itself.
38 |
39 | * **Use local variables.** JavaScript first searches to see if a variable exists locally, then searches progressively in higher levels of scope until global variables. Saving variables in a local scope allows JavaScript to access them much faster.
40 |
41 | * **Batching the DOM changes** Batch up DOM transformations to prevent recurring screen renderings. When creating style changes, make all the alterations at once instead of applying changes to each style individually. Furthermore, make style changes to a few elements directly rather than invalidating the page as a whole.
42 |
43 | * Avoid `setTimeout` or `setInterval` for visual updates; always use `requestAnimationFrame` instead.
44 |
45 | * Move long-running JavaScript off the main thread to Web Workers.
46 |
47 |
48 |
49 | #### References
50 |
51 | * https://blog.sessionstack.com/how-javascript-works-the-rendering-engine-and-tips-to-optimize-its-performance-7b95553baeda
52 | * https://developers.google.com/web/fundamentals/performance/rendering/
53 |
54 |
55 |
--------------------------------------------------------------------------------
/chapter/lang/python-guide.md:
--------------------------------------------------------------------------------
1 | ### Python Specific Advice
2 |
3 |
4 | #### OOP in Python
5 |
6 | * Use `raise NotImplementedError` to indicate abstract methods.
7 | * private attributes/functions should start with `_` in their name, e.g. `_secret`
8 |
9 |
10 |
11 | #### General Coding
12 |
13 | * Separate large numbers with underscores. Prefer `1_000_000` over `1000000`.
14 | * Use `_` for unused variables: `_, extension = 'foobar.txt'.split('.')`
15 | * constants are indicated by all uppercase names.
16 | * Create own types by assigning a base type to a name, e.g. `Volt = float`
17 |
18 |
19 |
20 | #### Further down the Pythonic road
21 |
22 | * Use context managers when reading files or acquiring locks/semaphores.\
23 | `with open('file.txt', 'r') as f:`
24 | * Use for-loops that iterate over what you actually need:
25 | - Elements: `for car in cars:`
26 | - Index and Element: `for idx, car in enumerate(cars):`
27 | - Elements of multiple lists: `for car, driver in zip(cars, drivers):`
28 |
29 |
30 | **Example**
31 | ```python
32 | class Employee(Person): # inheritance
33 | count = 0 # static attr. (shared by all instances)
34 |
35 | def __init__(self, name: str): # constructor
36 | super().__init__()
37 | Employee.count += 1
38 | self.name = name # local attr. (local to one instance)
39 |
40 | print(Employee.count)
41 | ```
42 |
43 |
--------------------------------------------------------------------------------
/res/img/architecture-bad.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/res/img/architecture-better.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/res/img/tum-ei-esi-header.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------