├── README.md └── assets ├── Cablespaghetti2.jpg └── clean-secure.jpg /README.md: -------------------------------------------------------------------------------- 1 | # 42 peer classes 2 | 3 |

4 | Amazing artwork 5 |

6 | 7 | ## Clean code 8 | 9 | > "Clean code can be read, and enhanced by a developer other than its original author. It has unit and acceptance tests. It has meaningful names. It provides one way rather than many ways for doing one thing. It has minimal dependencies, which are explicitly defined, and provides a clear and minimal API." 10 | 11 | All quotes are from [Clean code](https://www.goodreads.com/work/quotes/3779106-clean-code-a-handbook-of-agile-software-craftsmanship-robert-c-martin). 12 | 13 | ### Des spaghettis 14 | 15 |

16 | spaghetti 17 |

18 | 19 | - [Wiki: Syndrome du plat de spaghettis](https://fr.wikipedia.org/wiki/Syndrome_du_plat_de_spaghettis) 20 | - [Wiki: Programmation spaghetti](https://fr.wikipedia.org/wiki/Programmation_spaghetti) 21 | - [Wiki: Couplage (informatique)](https://fr.wikipedia.org/wiki/Couplage_(informatique)) 22 | 23 | -> Code spaghetti == Pas lisible 24 | 25 | ### Code lisible 26 | 27 | > "It is not the language that makes programs appear simple. It is the programmer that make the language appear simple!" 28 | > "Clean code is simple and direct. Clean code reads like well-written prose" 29 | 30 | - [Wiki: Programmation modulaire](https://fr.wikipedia.org/wiki/Programmation_modulaire) 31 | - [How to Organize Clean Architecture to Modular Patterns in 10 Minutes](https://www.codeproject.com/Articles/1210984/How-to-Organize-Clean-Architecture-to-Modular-Patt) 32 | 33 | Code propre : 34 | - facile à lire et à comprendre 35 | - modulaire 36 | - 1 fonction -> 1 action 37 | 38 | Si vous avez dans votre programme plusieurs passages qui font la même chose (voire, un passage que vous avez copié-collé à plusieurs endroits), alors il faut en faire une fonction. 39 | 40 | Pas bien : les fonctions super longues qui font beaucoup trop d'actions. 41 | 42 | Quelques termes clés : modulaire, monolithe, microservice, refactoring. 43 | 44 | Exemples : 45 | 46 | - https://gist.github.com/davidzchen/9187984 47 | - https://github.com/raspberrypi/linux/blob/rpi-5.4.y/fs/9p/acl.c 48 | - https://github.com/microsoft/WSL2-Linux-Kernel/blob/master/net/ipv4/arp.c (pour ce dernier exemple, on a par ex une variable nommée `dont_send` ligne 824, qui est un nom explicite) 49 | 50 | ### Bien nommer 51 | 52 | > "A long descriptive name is better than a long descriptive comment." 53 | 54 | - [Naming cheatsheet](https://github.com/kettanaito/naming-cheatsheet) 55 | 56 | Si vous ne savez pas comment nommer votre fonction ou votre variable, c'est que vous ne savez pas à quoi elle sert. 57 | 58 | Pas bien : 59 | 60 | - les noms pas clairs comme : n1, n2, n3 61 | - les noms trop abrégés : env_cpy -> ecpy 62 | - mix de mots Français-Anglais 63 | 64 | Choisir son format et s'y tenir : camelCase, snake_case, etc. Mais aussi comment on va par exemple nommer ses fonctions, ou aussi `if (!foo)` vs `if (foo == NULL)`. 65 | En bref, se tenir à un format facilite la lecture. 66 | 67 | Ne pas hésiter à faire des `define`. Il devrait y avoir le minimum de valeurs "en dur" dans le code. Les `define` permettent aussi de comprendre le programme quand on ne l'a jamais vu ou que l'on ne s'en souvient plus très bien. 68 | 69 | Exemple : Quelques mois après avoir rendu miniRT et minishell, vais-je me souvenir à quoi correspond ce `96`, ce `39.375` ou ce `256` ? Peut-être pas. Alors : 70 | 71 | ```c 72 | #define DEFAULT_DPI 96 73 | #define PPM_CONV_FACTOR 39.375 74 | #define MAX_STATES 256 75 | ``` 76 | 77 | **Exemples personnels et pour le C** 78 | 79 | Ce sont des exemples personnels, vous gérez comme vous le sentez. 80 | 81 | Pour les actions, j'aime bien nommer mes fonctions ainsi : `verbe_objet` 82 | - `start_shell()` 83 | - `trace_ray_to_objs()` 84 | - `get_word()` 85 | 86 | On peut faire aussi l'inverse : `objet_verbe` ou `objet_résultat` 87 | - `str_len()` 88 | - `str_dup()` 89 | - `stack_increase()` 90 | 91 | Pour les true/false : `objet_is_adjectif` ou `is_adjectif` 92 | - `stack_is_full()` 93 | - `stack_is_empty()` 94 | - `input_is_valid()` 95 | 96 | Cela clarifie la lecture : 97 | ```c 98 | if (stack_is_full(stack)) 99 | increase_stack(stack) 100 | ``` 101 | On comprend en lisant que si la pile est pleine, alors on augmente sa capacité. 102 | 103 | ### Bien ranger 104 | 105 | Séparer les .h, les .c et si possible les .o dans différents dossiers. 106 | 107 | Utiliser un fichier `.gitignore` afin de ne pas push les .o, les exécutables et d'autres fichiers pas utiles au projet comme `.DS_Store`. 108 | 109 | Dans un fichier C : 110 | - 1 fonction principale 111 | - ses auxiliaires (en statique en général) qui sont rarement appelées dans d'autres fichiers 112 | - les fonctions dans un fichier font une seule chose et travaillent ensemble 113 | 114 | Bien nommer ses fichiers C. Si besoin, créer des subdirs. 115 | Ce n'est pas obligatoire de split les .h mais c'est mieux surtout pour les plus gros projets et ça permet de réutiliser des parties d'un projet à l'autre. 116 | 117 | Exemple : si en évaluation, vous ne savez pas où retrouver une fonction, c'est que c'est mal rangé. 118 | 119 | Pas bien : les fichiers C avec 20 000 fonctions dedans de 42 000 lignes de long. 120 | 121 | ### Méthodologie 122 | 123 | D'abord se documenter, voire dessiner son programme, écrire des petits tests si besoin (exemple : des tests avec la mlx pour cub3D/miniRT). Savoir vers ce quoi on va même si le code va changer. Cette démarche va aussi permettre d'écrire le début des tests. 124 | 125 | - [Flowchart In Programming](https://www.programiz.com/article/flowchart-programming) 126 | - Flowcharts: [app.diagrams.net](https://app.diagrams.net/) 127 | 128 | ### Tester 129 | 130 | > "It is unit tests that keep our code flexible, maintainable, and reusable. The reason is simple. If you have tests, you do not fear making changes to the code! Without tests every change is a possible bug." 131 | 132 | - [Wiki: Test driven development](https://fr.wikipedia.org/wiki/Test_driven_development) 133 | 134 | Plusieurs types de tests : 135 | - **test unitaire / unit testing :** on vérifie le bon fonctionnement d'une partie précise, d'une "unité" 136 | - **test d'intégration / integration testing :** on intègre les modules testés à l'unité et on teste l'ensemble 137 | - **test de validation / acceptance testing :** on vérifie l'intégralité du logiciel et qu'il répond aux exigences exprimées par le client 138 | 139 | Faites vos propres tests et automatisez-les (Github Actions, Circle CI, Travis CI...). 140 | 141 | Il faut écrire les tests avant le programme en y allant petit à petit. 142 | 143 | - [Unit testing with asserts](http://www.electronvector.com/blog/unit-testing-with-asserts) 144 | 145 | ## Secure coding 146 | 147 | - [Guide ANSSI programmation en C](https://www.ssi.gouv.fr/guide/regles-de-programmation-pour-le-developpement-securise-de-logiciels-en-langage-c/) 148 | - [Secure Coding in C and C++](https://www.pearson.com/us/higher-education/program/Seacord-Secure-Coding-in-C-and-C-2nd-Edition/PGM142190.html) 149 | 150 | ### Malloc 151 | 152 | Quand on alloue, c'est mieux de set ensuite à zéro avec notamment bzero ou memset (utiliser ft_strnew() et ft_memalloc() par exemple). 153 | Quand on libère la mémoire, c'est mieux de set ensuite le pointeur à NULL (utiliser ft_strdel() et ft_memdel() par exemple). 154 | On ne cast normalement pas les malloc. 155 | 156 | Il faut bien set à NULL les variables au départ. 157 | 158 | Pas bien : 159 | ```c 160 | if( ! ( st_cur = (struct FT_CUSTOM *) malloc(sizeof( struct FT_CUSTOM ) ) ) ) 161 | { 162 | perror( "malloc failed" ); 163 | return( 1 ); 164 | } 165 | ``` 166 | 167 | Bien : 168 | ```c 169 | struct FT_CUSTOM * st_cur = NULL; 170 | 171 | st_cur = malloc( sizeof( struct FT_CUSTOM ) ); 172 | 173 | /* If the malloc succeeded it will have returned a valid 174 | * pointer to some part of the heap, otherwise it returns 175 | * NULL so we check for NULL here. */ 176 | if (st_cur == NULL) { 177 | /* Print a relevant error message to stderr. */ 178 | perror("malloc failed"); 179 | /* Return a non-zero value to indicate that something failed. */ 180 | return(1); 181 | } 182 | ``` 183 | -------------------------------------------------------------------------------- /assets/Cablespaghetti2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apt-42/peer_class/809b7efc9486ad1b3ca725ac13310ccabd9e31f9/assets/Cablespaghetti2.jpg -------------------------------------------------------------------------------- /assets/clean-secure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apt-42/peer_class/809b7efc9486ad1b3ca725ac13310ccabd9e31f9/assets/clean-secure.jpg --------------------------------------------------------------------------------