├── 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 | ![Bad Architecture.](res/img/architecture-bad.svg) 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 | ![Better Architecture.](res/img/architecture-better.svg) 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 | 131 | 132 | 133 | 158 |
Bad ❌Better ✔Better ✔
134 | 135 | ```python 136 | engine.start() 137 | nStartUps += 1 138 | if fuelTank.isEmpty(): 139 | fuelGaugeUI.setRedLED() 140 | ``` 141 | 142 | 143 | ```python 144 | engine.start() 145 | engine.runTest() 146 | warnings = engine.warnings() 147 | dashboard.show( warnings ) 148 | ``` 149 | 150 | 151 | ```python 152 | sys.test(): 153 | engine.test(): 154 | sparkPlug.test(): 155 | testIgnition() 156 | ``` 157 |
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 | 241 | 242 | 243 |
Bad ❌Better ✔
244 | 245 | ```c 246 | makeCircle(double r, double x, double y) 247 | ``` 248 | 249 | 250 | 251 | ```c 252 | makeCircle(Point center, double radius) 253 | ``` 254 | 255 |
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 | 271 | 272 |
Bad ❌Better ✔
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 | 283 | 284 | ```c 285 | Int totalIncome(employee){ 286 | salary = getSalary(employee) 287 | tax = getTax(employee) 288 | return (salary - tax) 289 | } 290 | ``` 291 | 292 |
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 | 378 | 379 |
Bad ❌Better ✔
380 | 381 | ```python 382 | score_list = [0] * scores 383 | for idx, val in score_list: 384 | score_list = val + 1 385 | ``` 386 | 387 | 388 | 389 | ```python 390 | scores = [0] * numScores 391 | for idx, score in scores: 392 | scores[idx] = score + 1 393 | ``` 394 | 395 |
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 | 492 | 493 |
Bad ❌Better ✔
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 | 503 | 504 | ```python 505 | if (isNightTime() and isPersonPresent()): 506 | turnLightOn() 507 | lockLight(TIMEOUT) # avoid flickering 508 | ``` 509 | 510 |
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 |
Vehicle
Vehicle
Monster Class
Monster Class
Dependency Hell
Dependency Hell
Engine
Engine
Gear
Gear
FuelTank
FuelTank
Throttle
Throttle
Dashboard
Dashboard
Engine
Engine
Gear
Gear
Dashboard
Dashboard
Throttle
Throttle
FuelTank
FuelTank
Light
Light
-velocity
+accel()
+brake(force)
+steer(angle) 

-velocity...
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /res/img/architecture-better.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Actor
Act...
Model
Model
Controller
Controller
View
View
changes
changes
notifies
notifies
shows
shows
requests
requests
FuelValve
FuelValve
Throttle
Throttle
Injector
Injector
SparkPlug
SparkPlug
MVC Triangle
MVC Triangle
Chain
Chain
Tree / Layers
Tree / Layers
Navigator
Navigator
Locator
Locator
Map
Map
Router
Router
Rules
Rules
IMU
IMU
GPS
GPS
Sensing
Sensing
Roads
Roads
Grid
Grid
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /res/img/tum-ei-esi-header.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Professorship of Embedded Systems and Internet of Things 5 | Department of Electrical and Computer Engineering 6 | Technical University of Munich 7 | 8 | --------------------------------------------------------------------------------