En aquest tema, explorarem els principis fonamentals que guien el disseny de programari robust, escalable i mantenible. Aquests principis són essencials per a qualsevol arquitecte de sistemes o desenvolupador que desitgi crear solucions tecnològiques eficients i efectives.

  1. Principis KISS (Keep It Simple, Stupid)

El principi KISS defensa la simplicitat en el disseny de programari. La idea és mantenir el codi tan simple com sigui possible per facilitar la comprensió, el manteniment i la modificació.

Exemples:

  • Codi Simple: Evitar la complexitat innecessària en el codi.
  • Funcions Curtes: Escriure funcions que facin una sola cosa i la facin bé.
# Exemple de funció simple
def calcular_area_rectangle(amplada, altura):
    return amplada * altura

  1. Principi DRY (Don't Repeat Yourself)

El principi DRY promou la reducció de la duplicació de codi. Quan un codi es repeteix, és més difícil de mantenir i actualitzar.

Exemples:

  • Reutilització de Codi: Crear funcions o mòduls reutilitzables.
  • Abstracció: Utilitzar classes i funcions per encapsular comportaments comuns.
# Exemple de reutilització de codi
def calcular_area_rectangle(amplada, altura):
    return amplada * altura

def calcular_area_quadrat(costat):
    return calcular_area_rectangle(costat, costat)

  1. Principi YAGNI (You Aren't Gonna Need It)

El principi YAGNI aconsella no implementar funcionalitats que no siguin necessàries en el moment. Això ajuda a mantenir el codi net i evita la complexitat innecessària.

Exemples:

  • Funcionalitats Essencials: Implementar només les funcionalitats que són necessàries ara.
  • Evitar Sobredisseny: No anticipar necessitats futures que poden no arribar mai.
# Exemple de codi sense funcionalitats innecessàries
def calcular_area_rectangle(amplada, altura):
    return amplada * altura

  1. Principi de Responsabilitat Única (SRP)

El principi de responsabilitat única estableix que una classe o mòdul ha de tenir una sola raó per canviar, és a dir, ha de tenir una única responsabilitat.

Exemples:

  • Classes Cohesionades: Cada classe ha de tenir una única responsabilitat.
  • Mòduls Independents: Dividir el codi en mòduls independents amb responsabilitats clares.
# Exemple de classe amb responsabilitat única
class GestorDeUsuaris:
    def crear_usuari(self, nom, correu):
        # Lògica per crear un usuari
        pass

class GestorDeCorreus:
    def enviar_correu(self, destinatari, assumpte, missatge):
        # Lògica per enviar un correu
        pass

  1. Principi de Substitució de Liskov (LSP)

El principi de substitució de Liskov estableix que els objectes d'una classe derivada han de poder substituir els objectes de la seva classe base sense alterar el comportament del programa.

Exemples:

  • Herència Correcta: Les subclasses han de complir amb el contracte establert per la classe base.
  • Polimorfisme: Utilitzar el polimorfisme per garantir la substituïbilitat.
# Exemple de principi de substitució de Liskov
class Animal:
    def fer_soroll(self):
        pass

class Gos(Animal):
    def fer_soroll(self):
        return "Bup Bup"

class Gat(Animal):
    def fer_soroll(self):
        return "Miau"

def fer_soroll_animal(animal):
    print(animal.fer_soroll())

gos = Gos()
gat = Gat()
fer_soroll_animal(gos)  # Bup Bup
fer_soroll_animal(gat)  # Miau

  1. Principi de Segregació d'Interfícies (ISP)

El principi de segregació d'interfícies estableix que els clients no han de dependre d'interfícies que no utilitzen. És millor tenir moltes interfícies específiques que una interfície general.

Exemples:

  • Interfícies Específiques: Crear interfícies petites i específiques per a cada funcionalitat.
  • Evitar Interfícies Grans: No crear interfícies que forcin els clients a implementar mètodes que no necessiten.
# Exemple de principi de segregació d'interfícies
class Imprimible:
    def imprimir(self):
        pass

class Escanejable:
    def escanejar(self):
        pass

class Impressora(Imprimible, Escanejable):
    def imprimir(self):
        print("Imprimint document")

    def escanejar(self):
        print("Escanejant document")

  1. Principi d'Inversió de Dependència (DIP)

El principi d'inversió de dependència estableix que els mòduls d'alt nivell no han de dependre dels mòduls de baix nivell. Ambdós han de dependre d'abstraccions.

Exemples:

  • Dependència d'Abstraccions: Utilitzar interfícies o classes abstractes per definir dependències.
  • Injecció de Dependències: Injectar les dependències a través de constructors o mètodes.
# Exemple de principi d'inversió de dependència
class Repositori:
    def guardar(self, dades):
        pass

class RepositoriSQL(Repositori):
    def guardar(self, dades):
        print("Guardant dades en SQL")

class Servei:
    def __init__(self, repositori: Repositori):
        self.repositori = repositori

    def processar(self, dades):
        self.repositori.guardar(dades)

repositori_sql = RepositoriSQL()
servei = Servei(repositori_sql)
servei.processar("Algunes dades")

Exercicis Pràctics

Exercici 1: Aplicar KISS i DRY

Refactoritza el següent codi per aplicar els principis KISS i DRY:

def calcular_area_rectangle(amplada, altura):
    return amplada * altura

def calcular_area_quadrat(costat):
    return costat * costat

def calcular_area_cercle(radi):
    return 3.14 * radi * radi

Solució:

def calcular_area_rectangle(amplada, altura):
    return amplada * altura

def calcular_area_quadrat(costat):
    return calcular_area_rectangle(costat, costat)

def calcular_area_cercle(radi):
    return 3.14 * radi * radi

Exercici 2: Aplicar SRP

Refactoritza el següent codi per aplicar el principi de responsabilitat única:

class GestorDeDocuments:
    def crear_document(self, contingut):
        # Lògica per crear un document
        pass

    def enviar_document(self, destinatari, document):
        # Lògica per enviar un document
        pass

Solució:

class GestorDeDocuments:
    def crear_document(self, contingut):
        # Lògica per crear un document
        pass

class GestorDeCorreus:
    def enviar_document(self, destinatari, document):
        # Lògica per enviar un document
        pass

Conclusió

Els principis de disseny de programari són fonamentals per crear sistemes robustos, escalables i fàcils de mantenir. Aquests principis ajuden a evitar la complexitat innecessària, promouen la reutilització del codi i asseguren que el programari sigui fàcil de modificar i estendre. En el proper tema, explorarem els patrons de disseny, que són solucions provades per a problemes comuns en el disseny de programari.

Arquitectures de Sistemes: Principis i Pràctiques per Dissenyar Arquitectures Tecnològiques Robustes i Escalables

Mòdul 1: Introducció a les Arquitectures de Sistemes

Mòdul 2: Principis de Disseny d'Arquitectures

Mòdul 3: Components d'una Arquitectura de Sistemes

Mòdul 4: Escalabilitat i Rendiment

Mòdul 5: Seguretat en Arquitectures de Sistemes

Mòdul 6: Eines i Tecnologies

Mòdul 7: Casos d'Estudi i Exemples Pràctics

Mòdul 8: Tendències i Futur de les Arquitectures de Sistemes

© Copyright 2024. Tots els drets reservats