diff --git a/20211230101331-software.org b/20211230101331-software.org index 8b70672..d55799c 100644 --- a/20211230101331-software.org +++ b/20211230101331-software.org @@ -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]] diff --git a/20220825074527-javascript.org b/20220825074527-javascript.org new file mode 100644 index 0000000..3887920 --- /dev/null +++ b/20220825074527-javascript.org @@ -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 diff --git a/20220825080435-diffsitter.org b/20220825080435-diffsitter.org new file mode 100644 index 0000000..843d674 --- /dev/null +++ b/20220825080435-diffsitter.org @@ -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]] diff --git a/20220908193040-solid.org b/20220908193040-solid.org new file mode 100644 index 0000000..6438730 --- /dev/null +++ b/20220908193040-solid.org @@ -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 doesn’t use, or clients shouldn’t 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]]