Add notes about Js, diffsitter and solid

This commit is contained in:
2022-09-10 13:39:41 +02:00
parent 18ea6afb94
commit 5d223655fc
4 changed files with 361 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
:PROPERTIES:
:ID: ca50d517-3e8a-4d03-ba38-7ff411e87408
:mtime: 20220602223012
:mtime: 20220910133708
:ctime: 20211230101331
:END:
#+title: Software
@@ -25,17 +25,21 @@ TODO
** Interprétés
*** [[id:a877b82e-4925-41de-8903-8109dd98e773][Bash]]
*** [[id:33ef1e68-70ad-43c8-850d-4b8ed2c5ea16][Elisp]]
*** [[id:d4197090-4ee5-4fa3-ba2d-a70ce9953923][Javascript]]
*** [[id:4fabfe6a-b104-464f-8a87-dfd7d761dbcc][Python]]
* Composition de docs
** [[id:3250943b-32f0-4bdc-b0d2-5fbcf1724f36][Latex]]
* Méthodes
* Méthodes/Principes
** [[id:b827c6e7-fe86-4301-a72c-dfaee85e142f][SOLID]]
** [[id:6da0b985-e6f4-4454-bb6a-e941b722365b][Test driven development]]
* Gestionnaire de versions
* Gestionnaire de configuration
** [[id:e93719b3-088d-4fe7-9ef8-fc9a4fd84827][Git]]
* Outils
** Diff
*** [[id:67317dba-3771-405f-ae58-0ef13062975d][diffsitter]]
** Performances
*** [[https://www.intel.com/content/www/us/en/developer/tools/oneapi/vtune-profiler.html#gs.26xa9e][Intel® VTune™ Profiler]]

View File

@@ -0,0 +1,12 @@
:PROPERTIES:
:ID: d4197090-4ee5-4fa3-ba2d-a70ce9953923
:mtime: 20220825074959
:ctime: 20220825074527
:END:
#+title: Javascript
* Introduction
Language interprété très largement utilisé pour les clients web. Il est aussi utilisé pour des applications backend ou
standalone via /v8/ ou [[https://deno.land/][Deno]].
* Références

View File

@@ -0,0 +1,14 @@
:PROPERTIES:
:ID: 67317dba-3771-405f-ae58-0ef13062975d
:mtime: 20220825080750
:ctime: 20220825080435
:END:
#+title: diffsitter
#+filetags: :TO_TRY:
* Introduction
Outil de diff basé sur l'analyse d'arbres AST plutôt que de chaines de caractères pour identifier les différences entre
deux fichiers contenant du code.
* Références
* [[https://github.com/afnanenayet/diffsitter][GitHub - afnanenayet/diffsitter: A tree-sitter based AST difftool to get meaningful semantic diffs]]

328
20220908193040-solid.org Normal file
View File

@@ -0,0 +1,328 @@
:PROPERTIES:
:ID: b827c6e7-fe86-4301-a72c-dfaee85e142f
:mtime: 20220910133550
:ctime: 20220908193040
:END:
#+title: SOLID
* Introduction
* Cinq principes de design de classes (P.O.O),
* Principes décrits par Robert J. Martin (a.k.a Uncle Bob) en 2000,
* Acronyme créé par Michael Feathers.
* Principes
** Responsabilité unique (Single responsability principle)
/A class should have one and only one reason to change, meaning that a class should have only one job./
Exemple de classe réalisant différentes tâches:
* Calcul du total de la facture (méthode ~calculate_total~),
* Impression de la facture (méthode ~print_invoice~),
* Sauvegarde de la facture (méthode ~save_to_file~).
#+BEGIN_SRC python :results output
class Invoice:
def __init__(self, book, quantity, discount_rate, tax_rate, total):
self.book = book
self.quantity = quantity
self.discount_rate = discount_rate
self.tax_rate = tax_rate
self.total = self.calculate_total()
def calculate_total(self):
price = (self.book.price - self.book.price * self.discount_rate) * self.quantity
price_with_taxe = price * (1 + self.tax_rate)
return price_with_taxe
def print_invoice(self):
print(f'{self.quantity}x {self.name} {self.price} $')
print(f'Discount Rate: {self.discount_rate}')
print(f'Tax Rate: {self.tax_rate}')
print(f'Total: {self.total}')
def save_to_file(self):
# Creates a file with given name and writes the invoice
...
#+END_SRC
Les erreurs :
* La logique d'impression d'une facture (méthode ~print_invoice~) devrait étre isolée : la seule raison pour laquelle
la classe ~Invoice~ devrait étre mise à jour est le changement de logique de calul du total (méthode
~calculate_total~).
* La logique de sauvegarde d'une facture (méthode ~save_to_file~) devrait elle aussi étre isolée : la classe ~Invoice~
ne devrait pas étre mise à jour suite au changement de méthode de sauvegarde (passage d'un fichier à une BDD par ex).
Une implémetation respectant le principe de *responsabilité unique* :
#+BEGIN_SRC python :results output
class Invoice:
def __init__(self, book, quantity, discount_rate, tax_rate, total):
self.book = book
self.quantity = quantity
self.discount_rate = discount_rate
self.tax_rate = tax_rate
self.total = self.calculate_total()
def calculate_total(self):
price = (self.book.price - self.book.price * self.discount_rate) * self.quantity
price_with_taxe = price * (1 + self.tax_rate)
return price_with_taxe
class InvoicePrinter:
def __init__(self, invoice):
self._invoice = invoice
def print(self):
print(f'{self._invoice.quantity}x {self._invoice.name} {self._invoice.price} $')
print(f'Discount Rate: {self._invoice.discount_rate}')
print(f'Tax Rate: {self._invoice.tax_rate}')
print(f'Total: {self._invoice.total}')
class InvoicePersistance:
def __init__(self, invoice):
self._invoice = invoice
def save_to_file(self):
# Creates a file with given name and writes the invoice
...
#+END_SRC
** Ouvert-fermé (Open-close principle)
/Objects or entities should be open for extension but closed for modification./
Une classe doit étre *ouverte pour l'extension* et *fermée pour les modifications* :
* Il doit étre possible d'ajouter une fonctionnalité à une classe sans modifier le code existant,
* Réalisé à l'aide d'interfaces et classes virtuelles,
Exemple de classe ne respesctant pas le principe :
#+BEGIN_SRC python :results output
class InvoicePersistance:
def __init__(self, invoice):
self._invoice = invoice
def save_to_file(self):
# Creates a file with given name and writes the invoice
...
def save_to_database(self):
# Save the invoice to database
...
#+END_SRC
Il ne devrait pas étre nécessaire de modifier la classe ~InvoicePersistance~ lorsqu'une nouvelle manière de sauvegarder
une ~Invoice~ est requise.
Une implémetation respectant le principe *ouvert/fermé* :
#+BEGIN_SRC python :results output
from abc import abstractmethod
class InvoicePersistance():
def __init__(self, invoice):
self._invoice = invoice
@abstractmethod
def save(self):
...
class FileInvoicePersistance(InvoicePersistance):
def save(self):
# Creates a file with given name and writes the invoice
...
class DatabaseInvoicePersistance(InvoicePersistance):
def save(self):
# Save the invoice to database
...
#+END_SRC
** Principe de substitution de Liskov
/Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T./
Les classes filles doivent pouvoir être substituées par leur classe mère :
* Pour une classe B, fille de A, il doit être possible de passer une instance de B à toute méthode s'attendant à avoir une instance de A, sans disfonctionnement.
#+BEGIN_SRC python :results output
class Rectangle:
def __init__(self, width, height):
self._width = width
self._height = height
@property
def width(self):
return self._width
@width.setter
def width(self, width):
self._width = width
@property
def height(self):
return self._height
@height.setter
def height(self, height):
self._height = height
def get_area(self):
return self._width * self._height
class Square(Rectangle):
def __init__(self, size):
super().__init__(size, size)
@Rectangle.width.setter
def width(self, size):
self._width = size
self._height = size
@Rectangle.height.setter
def height(self, size):
self._width = size
self._height = size
def test_get_area(rectangle):
width = rectangle.width
rectangle.height = 10
print(f'Expected area of {10 * width}, got {rectangle.get_area()}')
rectangle = Rectangle(2, 3)
test_get_area(rectangle)
square = Square(2)
square.width = 5
test_get_area(square)
#+END_SRC
#+RESULTS:
: Expected area of 20, got 20
: Expected area of 50, got 100
La classe ~Square~ ne respecte pas le principe car le comportement de la méthode ~get_area~ diffère selon l'instance de
classe passée en paramètre.
** Principe de ségrégation d'interface (Interface segregation principle)
/A client should never be forced to implement an interface that it doesnt use, or clients shouldnt be forced to depend on methods they do not use./
Il s'agit d'un principe de séparation des interfaces : plusieurs interfaces spécifiques sont meilleures qu'une unique
générale. Ainsi, seules les méthodes nécessaires sont implémentées et non l'intégralité de celles définies par
l'interface générique.
Exemple d'implémentation ne respectant pas le principe : l'interface ~ParkingLot~ englobe le stationnement
ainsi que le paiement. Quid de son implémentation pour le cas d'un parking gratuit ?
L'ideal serait d'isoler la partie paiement dans une interface dédiée.
#+BEGIN_SRC python :results output
from abc import abstractmethod
class Car:
...
class ParkingLot:
@abstractmethod
def park_car(self):
# Decrease empty spot count by 1
...
@abstractmethod
def unpark_car(self):
# Increase empty spot count by 1
...
@abstractmethod
def get_capacity(self):
# Return car capacity
...
@abstractmethod
def calculate_fee(self, car):
# Return the price based on the number of hours
...
@abstractmethod
def do_payment(self, car):
# Do the payment process for the computed fee
...
class FreeParking(ParkingLot):
def park_car(self):
...
def unpark_car(self):
...
def get_capacity(self):
...
def calculate_fee(self, car):
# Unused method here... the parking is free.
...
def do_payment(self, car):
# Unused method here... the parking is free.
...
#+END_SRC
** Principe d'inversion de dépendence (Dependency inversion principle)
/Entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the
low-level module, but they should depend on abstractions./
Les classes devraient être baséees sur des interfaces ou des classes abstraites plutôt que des classes concrètes,
#+BEGIN_SRC python :results output
class SqlConnection:
def connect(self):
...
class PasswordReminder:
def __init__(self, connection: SqlConnection) -> None:
...
#+END_SRC
La classe ~PasswordReminder~ ne doit pas avoir de couplage fort avec la méthode employée pour obtenir le mot de
passe. L'usage d'une interface permettrait d'abstraire la méthode de collecte.
#+BEGIN_SRC python :results outputs
from abc import abstractmethod
class Connection:
@abstractmethod
def connect(self):
...
class SqlConnection(Connection):
def connect(self):
...
class PasswordReminder:
def __init__(self, connection: Connection) -> None:
...
#+END_SRC
* Références
* [[https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf][Uncle bob design principes]]
* [[https://www.freecodecamp.org/news/solid-principles-explained-in-plain-english/][SOLID principes explained in plain english - freecodecamp.org]]