Finish (I think) SOLID principles
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details

This commit is contained in:
Fred Pauchet 2022-01-02 14:25:40 +01:00
parent 79d30a2902
commit 14e0f6c73a
9 changed files with 29 additions and 17 deletions

View File

@ -9,4 +9,4 @@ clean:
rm -rf $(BUILDDIR)/*
pdf:
asciidoctor-pdf -r asciidoctor-bibtex -a pdf-themesdir=resources/themes -a pdf-theme=book.yml source/main.adoc -t
asciidoctor-pdf -r asciidoctor-bibtex -a pdf-themesdir=resources/themes -a pdf-theme=book.yml source/main.adoc -t

View File

@ -75,7 +75,9 @@ include::part-1-workspace/_main.adoc[]
include::part-2-deployment/_main.adoc[]
include::part-3-django-concepts/_index.adoc[]
include::part-3-data-model/_index.adoc[]
include::part-4-services-oriented-applications/_main.adoc[]
include::part-5-go-live/_index.adoc[]

View File

@ -42,7 +42,7 @@ class CustomUserClass:
...
----
cite:{expert_python, 142-144}
cite:[expert_python(142-144)]
Ces méthodes, utilisées seules ou selon des combinaisons spécifiques, constituent les _protocoles de langage_.
Une liste complètement des _dunder methods_ peut être trouvée dans la section `Data Model` de https://docs.python.org/3/reference/datamodel.html[la documentation du langage Python].
@ -178,7 +178,7 @@ Si vous ne voulez pas être dérangé sur votre manière de coder, et que vous v
Python étant un langage interprété fortement typé, il est plus que conseillé, au même titre que les tests unitaires que nous verrons plus bas, de documenter son code.
Cela impose une certaine rigueur, mais améliore énormément la qualité, la compréhension et la reprise du code par une tierce personne.
Cela implique aussi de **tout** documenter: les modules, les paquets, les classes, les fonctions, méthodes, ...
Ce qui peut également aller à contrecourant d'autres pratiques cite:[clean_code,53-74]; il y a une juste mesure à prendre entre "tout documenter" et "tout bien documenter":
Ce qui peut également aller à contrecourant d'autres pratiques cite:[clean_code(53-74)]; il y a une juste mesure à prendre entre "tout documenter" et "tout bien documenter":
* Inutile d'ajouter des watermarks, auteurs, ... Git ou tout VCS s'en sortira très bien et sera beaucoup plus efficace que n'importe quelle chaîne de caractères que vous pourriez indiquer et qui sera fausse dans six mois,
* Inutile de décrire quelque chose qui est évident; documenter la méthode `get_age()` d'une personne n'aura pas beaucoup d'intérêt
@ -1099,4 +1099,4 @@ Parfois, SQLite peut être une bonne option:
Write througput is the area where SQLite struggles the most, but there's not a ton of compelling data online about how it fares, so I got some of my own: I spun up a Equinix m3.large.x86 instance, and ran a slightly modified1 version of the SQLite kvtest2 program on it. Writing 512 byte blobs as separate transactions, in WAL mode with synchronous=normal3, temp_store=memory, and mmap enabled, I got 13.78μs per write, or ~72,568 writes per second. Going a bit larger, at 32kb writes, I got 303.74μs per write, or ~3,292 writes per second. That's not astronomical, but it's certainly way more than most websites being used by humans need. If you had 10 million daily active users, each one could get more than 600 writes per day with that.
[quote]
Looking at read throughput, SQLite can go pretty far: with the same test above, I got a read throughput of ~496,770 reads/sec (2.013μs/read) for the 512 byte blob. Other people also report similar results — Expensify reports that you can get 4M QPS if you're willing to make some slightly more involved changes and use a beefier server. Four million QPS is enough that every internet user in the world could make ~70 queries per day, with a little headroom left over4. Most websites don't need that kind of throughput. cite:{consider_sqlite}
Looking at read throughput, SQLite can go pretty far: with the same test above, I got a read throughput of ~496,770 reads/sec (2.013μs/read) for the 512 byte blob. Other people also report similar results — Expensify reports that you can get 4M QPS if you're willing to make some slightly more involved changes and use a beefier server. Four million QPS is enough that every internet user in the world could make ~70 queries per day, with a little headroom left over4. Most websites don't need that kind of throughput. cite:[consider_sqlite]

View File

@ -57,7 +57,9 @@ votre nouvelle création en utilisant Django, vous serez bon gré mal gré, cont
Cette décision ne sera pas irrévocable, mais difficile à contourner.
> At some point in their history most DevOps organizations were hobbled by tightly-coupled, monolithic architectures that while extremely successfull at helping them achieve product/market fit - put them at risk of organizational failure once they had to operate at scale (e.g. eBay's monolithic C++ application in 2001, Amazon's monolithic OBIDOS application in 2001, Twitter's monolithic Rails front-end in 2009, and LinkedIn's monolithic Leo application in 2011).
> In each of these cases, they were able to re-architect their systems and set the stage not only to survice, but also to thrise and win in the marketplace cite:[devops_handbook(182)]
> In each of these cases, they were able to re-architect their systems and set the stage not only to survice, but also to thrise and win in the marketplace
cite:[devops_handbook(182)]
Ceci dit, Django compense ses contraintes en proposant énormément de flexibilité et de fonctionnalités
*out-of-the-box*, c'est-à-dire que vous pourrez sans doute avancer vite et bien jusqu'à un point de rupture,

View File

@ -2,7 +2,9 @@
> Un code mal pensé entraîne nécessairement une perte d'énergie et de temps.
> Il est plus simple de réfléchir, au moment de la conception du programme, à une architecture permettant une meilleure maintenabilité que de devoir corriger un code "sale" _a posteriori_.
> C'est pour aider les développeurs à rester dans le droit chemin que les principes SOLID ont été énumérés. GNU/Linux Magazine HS 104 cite:{gnu_linux_mag_hs_104, 26-44}
> C'est pour aider les développeurs à rester dans le droit chemin que les principes SOLID ont été énumérés. GNU/Linux Magazine HS 104
cite:[gnu_linux_mag_hs_104(26-44)]
Les principes SOLID, introduit par Robert C. Martin dans les années 2000 sont les suivants:
@ -22,16 +24,18 @@ En plus de ces principes de développement, il faut ajouter des principes au niv
==== Single Responsibility Principle
Le principe de responsabilité unique conseille de disposer de concepts ou domaines d'activité qui ne s'occupent chacun que d'une et une seule chose.
Ceci rejoint un peu la https://en.wikipedia.org/wiki/Unix_philosophy[Philosophie Unix], documentée par Doug McIlroy et qui demande de "_faire une seule chose, mais le faire bien_" cite:{unix_philosophy}.
Ceci rejoint un peu la https://en.wikipedia.org/wiki/Unix_philosophy[Philosophie Unix], documentée par Doug McIlroy et qui demande de "_faire une seule chose, mais le faire bien_" cite:[unix_philosophy].
Une classe ou un élément de programmtion ne doit donc pas avoir plus d'une raison de changer.
Il est également possible d'étendre ce principe en fonction d'acteurs:
> A module should be responsible to one and only one actor cite:{clean_architecture}
> A module should be responsible to one and only one actor.
cite:[clean_architecture]
Plutôt que de centraliser le maximum de code à un seul endroit ou dans une seule classe par convenance ou commodité footnote:[Aussi appelé _God-Like object_], le principe de responsabilité unique suggère que chaque classe soit responsable d'un et un seul concept.
Une autre manière de voir les choses consiste à différencier les acteurs ou les intervenants: imaginez avoir une classe représentant des données de membres du personnel.
Ces données pourraient être demandées par trois acteurs, le CFO, le CTO et le COO: ceux-ci ont tous besoin de données et d'informations relatives à une même base de données centralisées, mais ont chacun besoin d'une représentation différente ou de traitements distincts. cite:{clean_architecture}
Ces données pourraient être demandées par trois acteurs, le CFO, le CTO et le COO: ceux-ci ont tous besoin de données et d'informations relatives à une même base de données centralisées, mais ont chacun besoin d'une représentation différente ou de traitements distincts. cite:[clean_architecture]
Nous sommes daccord quil sagit à chaque fois de données liées aux employés, mais elles vont un cran plus loin et pourraient nécessiter des ajustements spécifiques en fonction de lacteur concerné.
Lidée sous-jacente est simplement didentifier dès que possible les différents acteurs, en vue de prévoir une modification qui pourrait être demandée par lun dentre eux.
Dans le cas d'un élément de code centralisé, une modification induite par un des acteurs pourrait ainsi avoir un impact sur les données utilisées par les autres.
@ -342,7 +346,7 @@ Ce principe stipule qu'un client ne doit pas dépendre d'une méthode dont il n'
Plus simplement, plutôt que de dépendre d'une seule et même (grosse) interface présentant un ensemble conséquent de méthodes, il est proposé d'exploser cette interface en plusieurs (plus petites) interfaces.
Ceci permet aux différents consommateurs de n'utiliser qu'un sous-ensemble précis d'interfaces, répondant chacune à un besoin précis.
GNU/Linux Magazine cite:{gnu_linux_mag_hs_104, 37-42} propose un exemple d'interface permettant d'implémenter une imprimante:
GNU/Linux Magazine cite:[gnu_linux_mag_hs_104(37-42)] propose un exemple d'interface permettant d'implémenter une imprimante:
[source,java]
----
@ -508,7 +512,9 @@ L'inversion de dépendances stipule que c'est le composant de haut-niveau qui po
Lobjectif est que les interfaces soient les plus stables possibles, afin de réduire au maximum les modifications qui pourraient y être appliquées.
De cette manière, toute modification fonctionnelle pourra être directement appliquée sur le composant de bas-niveau, sans que l'interface ne soit impactée.
> The dependency inversion principle tells us that the most flexible systems are those in which source code dependencies refer only to abstractions, not to concretions. cite:{clean_architecture}
> The dependency inversion principle tells us that the most flexible systems are those in which source code dependencies refer only to abstractions, not to concretions.
cite:[clean_architecture]
L'injection de dépendances est un patron de programmation qui suit le principe d'inversion de dépendances.
@ -559,7 +565,9 @@ Dans d'autres projets écrits en Python, ce type de mécanisme peut être implé
Un autre exemple concerne les bases de données: pour garder un maximum de flexibilité, Django ajoute une couche d'abstraction en permettant de spécifier le moteur de base de données que vous souhaiteriez utiliser, qu'il s'agisse d'SQLite, MSSQL, Oracle, PostgreSQL ou MySQL/MariaDB footnote:[http://howfuckedismydatabase.com/].
> The database is really nothing more than a big bucket of bits where we store our data on a long term basis cite:{clean_architecture, 281}.
> The database is really nothing more than a big bucket of bits where we store our data on a long term basis.
cite:[clean_architecture(281)]
Dun point de vue architectural, nous ne devons pas nous soucier de la manière dont les données sont stockées, sil sagit dun disque magnétique, de ram, ... en fait, on ne devrait même pas savoir sil y a un disque du tout.
Et Django le fait très bien pour nous.

View File

@ -15,7 +15,7 @@ Lobjectif est qu'il soit rapide et fiable.
Ceci peut être atteint au travers dun partitionnement correct, incluant le fait que le composant principal sassure que chaque sous-composant est correctement démarré intégré et supervisé.
Aborder le déploiement dès le début permet également de rédiger dès le début les procédures d'installation, de mises à jour et de sauvegardes.
A la fin de chaque intervalle de développement, les fonctionnalités auront dû avoir été intégrées, testées, fonctionnelles et un code propre, démontrable dans un environnement similaire à un environnement de production, et créées à partir d'un tronc commun au développement cite:{devops_handbook}.
A la fin de chaque intervalle de développement, les fonctionnalités auront dû avoir été intégrées, testées, fonctionnelles et un code propre, démontrable dans un environnement similaire à un environnement de production, et créées à partir d'un tronc commun au développement cite:[devops_handbook].
Déploier une nouvelle version sera aussi simple que de récupérer la dernière archive depuis le dépôt, la placer dans le bon répertoire, appliquer des actions spécifiques (et souvent identiques entre deux versions), puis redémarrer les services adéquats, et la procédure complète se résumera à quelques lignes d'un script bash.

View File

@ -105,7 +105,7 @@ class Circle(Shape):
----
On le voit: une structure brute peut être rendue abstraite au travers des notions de programmation orientée objet.
Dans l'exemple géométrique ci-dessus, repris de cite:[clean_code, 95-97], l'accessibilité des champs devient restreinte, tandis que la fonction `area()` bascule comme méthode d'instance plutôt que de l'isoler au niveau d'un visiteur.
Dans l'exemple géométrique ci-dessus, repris de cite:[clean_code(95-97)], l'accessibilité des champs devient restreinte, tandis que la fonction `area()` bascule comme méthode d'instance plutôt que de l'isoler au niveau d'un visiteur.
Nous ajoutons une abstraction au niveau des formes grâce à un héritage sur la classe `Shape`; indépendamment de ce que nous manipulerons, nous aurons la possibilité de calculer son aire.
Une structure de données permet de facilement gérer des champs et des propriétés, tandis qu'une classe gère et facilite l'ajout de fonctions et de méthodes.

View File

@ -15,7 +15,7 @@ Les *tests d'acceptance* vérifient que l'application fonctionne comme convenu,
Les *tests d'intégration* vérifient que l'application coopère correctement avec les systèmes périphériques.
De manière plus générale, si nous nous rendons compte que les tests sont trop compliqués à écrire ou nous coûtent trop de temps, c'est sans doute que l'architecture de la solution n'est pas adaptée et que les composants sont couplés les uns aux autres. Dans ces cas, il sera nécessaire de refactoriser le code, afin que chaque module puisse être testé indépendamment des autres. cite:{clean_architecture}
De manière plus générale, si nous nous rendons compte que les tests sont trop compliqués à écrire ou nous coûtent trop de temps, c'est sans doute que l'architecture de la solution n'est pas adaptée et que les composants sont couplés les uns aux autres. Dans ces cas, il sera nécessaire de refactoriser le code, afin que chaque module puisse être testé indépendamment des autres. cite:[clean_architecture]
[quote,Robert C. Martin, Clean Architecture]
Martin Fowler observes that, in general, "a ten minute build [and test process] is perfectly within reason...

View File

@ -98,7 +98,7 @@
url = {https://simpleisbetterthancomplex.com/series/beginners-guide/1.11/}
}
@misc{gnu_linux_mag_hs_104,
title = {Les cinq règles pour écrire du code maintenable}
title = {Les cinq règles pour écrire du code maintenable},
year = {2019},
url = {https://boutique.ed-diamond.com/les-hors-series/1402-gnulinux-magazine-hs-104.html}
}