miércoles, 13 de noviembre de 2024

Arquitectura hexagonal (HA): integrando principios SOLID desde 2008

La Arquitectura Hexagonal, también conocida como Puertos y Adaptadores, del Dr. Alistair Cockburn 2006, es un enfoque y propuesta de diseño de software basado en el #solidprinciples. Estos principios #SOLID son un conjunto de cinco principios de diseño que promueven la creación de código limpio, flexible y mantenible. La H.A. expone que podríamos dividir nuestro Proyecto de Arquitectura. Exploremos cómo HA. se alinea con los principios SOLID en varios puntos clave.

Es importante recalcar que HA no es reciente y ha estado en proceso desde antes de 2008, cuando comencé a aplicarlo. Si bien es posible que no se haya referido a él como HA en ese momento, los principios subyacentes ya se estaban aplicando en nuestra comunidad antes de 2006. La idea central de separar la lógica empresarial de las preocupaciones técnicas y de infraestructura ha sido un tema de interés durante más de dos décadas. Con el paso de los años, ha ido evolucionando y perfeccionándose, adquiriendo diversos nombres como "Puertos y Adaptadores" y "Arquitectura Hexagonal". Esto es efectivo en aplicaciones donde la flexibilidad es esencial (spoiler: #messagebroker, #workflow o #microservices).

 

1. Principio de Responsabilidad Única | Single Responsibility Principle SRP:

HA tiene como objetivo separar las responsabilidades de la lógica empresarial de las preocupaciones técnicas, como la persistencia de los datos o la interfaz de usuario. Esto se logra mediante la creación de adaptadores responsables de interactuar con estas preocupaciones técnicas, permitiendo que los puertos se concentren únicamente en sus cosas.

2. Principio Abierto/Cerrado | Open/Closed Principle OCP:

HA promueve la extensibilidad y la flexibilidad. Los puertos definen interfaces que pueden implementarse y deben implementarse mediante múltiples adaptadores (clases que hacen que suceda la magia). Cuando se requiere nueva funcionalidad, se pueden crear nuevos adaptadores para implementar estas interfaces sin modificar el código existente en los puertos. Esto cumple con el OCP, lo que permite la extensión sin alterar el código existente.

3. Principio de sustitución de Liskov | Liskov Substitution Principle LSP:

Al definir interfaces en los puertos, los adaptadores deben cumplir con estas interfaces. Esto garantiza que los adaptadores sean intercambiables sin afectar el comportamiento del sistema. El cumplimiento del LSP permite la sustitución de adaptadores sin cambios en la lógica de la aplicación principal.

4. Principio de segregación de interfaces | Interface Segregation Principle ISP:

En HA las interfaces en los puertos se mantienen específicas para las necesidades de los clientes. Esto evita que los clientes se vean obligados a implementar métodos no utilizados. Al dividir las interfaces en puertos según las necesidades de los clientes, se logra el cumplimiento del ISP.

5. Principio de inversión de dependencia | Dependency Inversion Principle DIP:

HA. invierte las dependencias al permitir que los puertos definan las interfaces que implementan los adaptadores. Esto significa que los puertos no dependen de implementaciones concretas sino de abstracciones (las interfaces). Aplicar el DIP facilita la sustituibilidad de los componentes mejorando la mantenibilidad, la flexibilidad, facilitando la solidez de la solución y ahorrando dinero en tiempo.

Cabecera

Fuentes:

 Para conocer más sobre esta arquitectura consulta el creador del termino Alistair Cockburn en archive.org , ya que, el su web está en actualización alistair.cockburn.us.

 Robert C. Martin (Uncle Bob)

 

miércoles, 13 de noviembre de 2019

Libros relacionados con la gnosis

La gnosis.

Un conjunto de corrientes espirituales y filosóficas que buscan la comprensión directa y trascendental de la realidad, generalmente a través de la experiencia mística o la revelación interior. Los textos más importantes de la gnosis provienen de una variedad de tradiciones, principalmente del cristianismo primitivo, el hermetismo, el maniqueísmo y el gnosticismo helenístico. Aquí menciono algunos de los libros y textos más relevantes relacionados con la gnosis:

  1. Evangelios gnósticos.

    Muchos textos gnósticos fueron descubiertos en el siglo XX, especialmente con el hallazgo de los Manuscritos de Nag Hammadi (1945) en Egipto. Estos evangelios ofrecen una visión alternativa y más esotérica de las enseñanzas de Jesús, en contraste con los textos canónicos del Nuevo Testamento.

    El Evangelio de Tomás: Un conjunto de 114 dichos de Jesús, muchos de los cuales enfatizan el conocimiento interior y la autotransformación.
    El Evangelio de Felipe: Un texto que aborda temas de la naturaleza del alma, la relación entre lo divino y lo humano, y los sacramentos.
    El Evangelio de la Verdad: Un texto atribuido a Valentín, que presenta una visión mística de la verdad, el conocimiento y la creación.
    El Evangelio de María Magdalena: Aunque fragmentario, este evangelio destaca el papel de María Magdalena como una figura clave en la transmisión del conocimiento secreto de Jesús.


  2. La "Apocalipsis" de Juan.

    En los primeros tiempos del cristianismo, este texto fue considerado un apocalipsis de corte gnóstico, ya que sus visiones del mundo están impregnadas de simbolismo esotérico y conocimiento oculto. Aunque en gran parte se incluyó en el canon cristiano, es relevante para estudios gnósticos por sus descripciones de la lucha espiritual y el conocimiento superior.

  3. El "Corpus Hermeticum

    Una serie de textos que exploran la filosofía hermética, el conocimiento divino y la transformación del alma. Aunque no es estrictamente un texto gnóstico, comparte muchas ideas fundamentales, como la búsqueda de la sabiduría esotérica y la salvación a través del conocimiento. Se le atribuye a Hermes Trismegisto, una figura mítica que combina elementos de Hermes (dios griego) y Thoth (dios egipcio).
     
  4. El "Libro de los Secretos de Enoch


    También conocido como el "Segundo Libro de Enoc", este texto apócrifo judío (no parte del canon bíblico) describe una ascensión mística al cielo de Enoc, un personaje bíblico. En él se exponen conocimientos esotéricos sobre la naturaleza del universo, los ángeles y las jerarquías divinas, características comunes de la gnosis.

  5. Los textos de Nag Hammadi

    Estos textos son una compilación clave de la literatura gnóstica descubierta en 1945, y son fundamentales para entender el pensamiento gnóstico. Algunos de los más importantes incluyen:
    • El Tratado Tripartito
    • El Apócrifo de Juan
    • La Carta de Pedro a Felipe
     
  6. La Pistis Sophia

    Es un texto gnóstico cristiano muy influyente que describe la historia de la caída de Sophia (sabiduría) y su búsqueda de redención a través del conocimiento. La obra trata sobre la relación entre la humanidad, el mundo material, y las entidades espirituales, y cómo el alma puede ser redimida por medio del conocimiento.
     
  7. El Zohar" (La Esplendidez)

    Aunque es un texto central en la **Cábala judía** y no se clasifica estrictamente como gnóstico, contiene ideas que se superponen con la gnosis, especialmente en lo que respecta a la naturaleza oculta de Dios, el alma y el conocimiento divino. Es fundamental para aquellos que exploran el esoterismo y las tradiciones místicas.
     
  8. Las enseñanzas de Plotino.

    Plotino, el filósofo neoplatónico, influyó profundamente en el desarrollo de la gnosis. Su obra más importante es las **Enéadas**, que explora la naturaleza de la realidad, el alma, la divinidad, y la búsqueda del conocimiento trascendental.
     
  9. La doctrina secreta" de Helena Blavatsky.

    Aunque no es un texto antiguo, **Helena Petrovna Blavatsky**, cofundadora de la Sociedad Teosófica, es una figura clave en el renacer moderno del esoterismo y la gnosis. Su obra **La doctrina secreta** explora conocimientos ocultos sobre la creación, la humanidad y el cosmos desde una perspectiva mística y gnóstica.

  10. El libro tibetano de los muertos.

    Aunque es un texto budista tibetano, muchas de sus enseñanzas, que tratan sobre el despertar espiritual y el conocimiento de la muerte y el más allá, resuenan con la tradición gnóstica en su énfasis en la iluminación personal y el conocimiento de la realidad última.

¿Qué caracteriza a estos textos

Los textos gnósticos generalmente comparten temas comunes, tales como:

  • El dualismo: La lucha entre el bien y el mal, la luz y la oscuridad, lo espiritual y lo material.
  • El conocimiento esotérico: La idea de que solo unos pocos iniciados pueden alcanzar el conocimiento verdadero.
  • El desprecio por lo material: La visión de que el mundo material es imperfecto, corrupto o incluso ilusorio.
  • La salvación a través del conocimiento: La liberación del alma solo se alcanza mediante el conocimiento directo y trascendental.


Estos libros han tenido una influencia duradera en la filosofía occidental, las religiones místicas, y las tradiciones esotéricas que siguen hasta nuestros días.

 

lunes, 7 de mayo de 2018

Abstract Factory design pattern with both interfaces and enumerations approaches. Examples in some popular languages.

The Abstract Factory design pattern is a creational pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. Below is a Java implementation of the Abstract Factory design pattern.

Implementation of Abstract Factory Pattern

  1. Abstract Factory Interface: Defines methods for creating abstract products.
  2. Concrete Factories: Implement the creation of specific families of products.
  3. Abstract Product Interfaces: Define the types of products.
  4. Concrete Products: Implement the abstract product interfaces.
  5. Client Code: Uses the factory and products through their interfaces.

 



Example 1: Abstract Factory with Interfaces in Java

Below is an example implementation of the Abstract Factory pattern using interfaces in a banking context for creating different types of loans.

// Abstract Factory
interface LoanFactory {
    Loan createLoan();
}

// Abstract Product
interface Loan {
    void getDetails();
}

// Concrete Products
class MortgageLoan implements Loan {
    @Override
    public void getDetails() {
        System.out.println("This is a Mortgage Loan.");
    }
}

class PersonalLoan implements Loan {
    @Override
    public void getDetails() {
        System.out.println("This is a Personal Loan.");
    }
}

class AutoLoan implements Loan {
    @Override
    public void getDetails() {
        System.out.println("This is an Auto Loan.");
    }
}

// Concrete Factories
class MortgageLoanFactory implements LoanFactory {
    @Override
    public Loan createLoan() {
        return new MortgageLoan();
    }
}

class PersonalLoanFactory implements LoanFactory {
    @Override
    public Loan createLoan() {
        return new PersonalLoan();
    }
}

class AutoLoanFactory implements LoanFactory {
    @Override
    public Loan createLoan() {
        return new AutoLoan();
    }
}

// Client
public class BankingApplication {
    public static void main(String[] args) {
        LoanFactory mortgageFactory = new MortgageLoanFactory();
        Loan mortgageLoan = mortgageFactory.createLoan();
        mortgageLoan.getDetails();

        LoanFactory personalFactory = new PersonalLoanFactory();
        Loan personalLoan = personalFactory.createLoan();
        personalLoan.getDetails();

        LoanFactory autoFactory = new AutoLoanFactory();
        Loan autoLoan = autoFactory.createLoan();
        autoLoan.getDetails();
    }
}

Example 2: Abstract Factory with Enumerations in Java

This example uses enums to manage the loan creation logic. Each enum instance acts as a factory.

// Abstract Product
abstract class Loan {
    abstract void getDetails();
}

// Concrete Products
class MortgageLoan extends Loan {
    @Override
    void getDetails() {
        System.out.println("This is a Mortgage Loan.");
    }
}

class PersonalLoan extends Loan {
    @Override
    void getDetails() {
        System.out.println("This is a Personal Loan.");
    }
}

class AutoLoan extends Loan {
    @Override
    void getDetails() {
        System.out.println("This is an Auto Loan.");
    }
}

// Abstract Factory using Enum
enum LoanFactory {
    MORTGAGE {
        @Override
        public Loan createLoan() {
            return new MortgageLoan();
        }
    },
    PERSONAL {
        @Override
        public Loan createLoan() {
            return new PersonalLoan();
        }
    },
    AUTO {
        @Override
        public Loan createLoan() {
            return new AutoLoan();
        }
    };

    public abstract Loan createLoan();
}

// Client
public class BankingApplicationWithEnum {
    public static void main(String[] args) {
        Loan mortgageLoan = LoanFactory.MORTGAGE.createLoan();
        mortgageLoan.getDetails();

        Loan personalLoan = LoanFactory.PERSONAL.createLoan();
        personalLoan.getDetails();

        Loan autoLoan = LoanFactory.AUTO.createLoan();
        autoLoan.getDetails();
    }
}

Key Points:

  1. Using Interfaces:

    • Provides flexibility and extensibility by allowing additional types of loans and factories without modifying existing code.
    • Clear separation of concerns with individual factory classes for each loan type.
  2. Using Enumerations:

    • Simplifies factory management as enum constants inherently represent different factories.
    • Reduces the overhead of creating multiple factory classes but is less flexible for large-scale systems.

  

Advantages and disadvantages of using


Advantages

  1. Encapsulation of Object Creation:

    • Hides the details of how objects are created and assembled, making code cleaner and easier to manage.
  2. Consistency:

    • Ensures that products created by the factory are compatible with each other (e.g., objects from the same family).
  3. Scalability:

    • Adding new product families is straightforward. You can add a new factory and corresponding products without altering existing code.
  4. Flexibility:

    • Decouples client code from concrete implementations, allowing easy swapping of product families by simply changing the factory instance.
  5. Promotes Dependency Inversion Principle:

    • Clients depend on abstractions (interfaces or abstract classes) rather than concrete classes, enhancing testability and maintainability.
  6. Centralized Creation Logic:

    • All object creation is handled in one place, making it easier to update or modify.

Disadvantages

  1. Complexity:

    • Introduces additional layers of abstraction and requires more classes and interfaces, which can make the system more complex.
  2. Difficult to Extend Individual Products:

    • Modifying or adding a single product in a family may require changes in all the factories or creating a new product family.
  3. Overhead for Small Systems:

    • In systems with limited object types or families, the pattern can be overkill and unnecessarily increase codebase size.
  4. Coupling Between Factories and Products:

    • Factories are tightly coupled to the specific product hierarchies they create, which can limit flexibility in some cases.
  5. Rigid Structure:

    • While adding a new family is straightforward, adding support for a new product across existing families can be cumbersome as it may require changes to all factories.

When to Use Abstract Factory

  • Use the Abstract Factory pattern when:

    • The system needs to work with multiple families of related objects.
    • You want to isolate the creation process of objects from their usage.
    • Ensuring compatibility among objects is a priority.
    • There’s a need to change the product family dynamically at runtime.
  • Avoid using the pattern when:

    • The system has simple requirements with few types of objects.
    • The overhead of creating factories and products outweighs the benefits.

 


Example 1: Abstract Factory with Interfaces in C#

Below is the implementation of the Abstract Factory pattern using interfaces in C#.

// Abstract Factory
public interface ILoanFactory
{
    ILoan CreateLoan();
}

// Abstract Product
public interface ILoan
{
    void GetDetails();
}

// Concrete Products
public class MortgageLoan : ILoan
{
    public void GetDetails()
    {
        Console.WriteLine("This is a Mortgage Loan.");
    }
}

public class PersonalLoan : ILoan
{
    public void GetDetails()
    {
        Console.WriteLine("This is a Personal Loan.");
    }
}

public class AutoLoan : ILoan
{
    public void GetDetails()
    {
        Console.WriteLine("This is an Auto Loan.");
    }
}

// Concrete Factories
public class MortgageLoanFactory : ILoanFactory
{
    public ILoan CreateLoan()
    {
        return new MortgageLoan();
    }
}

public class PersonalLoanFactory : ILoanFactory
{
    public ILoan CreateLoan()
    {
        return new PersonalLoan();
    }
}

public class AutoLoanFactory : ILoanFactory
{
    public ILoan CreateLoan()
    {
        return new AutoLoan();
    }
}

// Client
public class BankingApplication
{
    public static void Main(string[] args)
    {
        ILoanFactory mortgageFactory = new MortgageLoanFactory();
        ILoan mortgageLoan = mortgageFactory.CreateLoan();
        mortgageLoan.GetDetails();

        ILoanFactory personalFactory = new PersonalLoanFactory();
        ILoan personalLoan = personalFactory.CreateLoan();
        personalLoan.GetDetails();

        ILoanFactory autoFactory = new AutoLoanFactory();
        ILoan autoLoan = autoFactory.CreateLoan();
        autoLoan.GetDetails();
    }
}

Example 2: Abstract Factory with Enumerations in C#

This example uses enumerations to manage loan creation logic in C#.

// Abstract Product
public abstract class Loan
{
    public abstract void GetDetails();
}

// Concrete Products
public class MortgageLoan : Loan
{
    public override void GetDetails()
    {
        Console.WriteLine("This is a Mortgage Loan.");
    }
}

public class PersonalLoan : Loan
{
    public override void GetDetails()
    {
        Console.WriteLine("This is a Personal Loan.");
    }
}

public class AutoLoan : Loan
{
    public override void GetDetails()
    {
        Console.WriteLine("This is an Auto Loan.");
    }
}

// Abstract Factory using Enum
public enum LoanFactory
{
    MORTGAGE,
    PERSONAL,
    AUTO
}

public static class LoanFactoryExtensions
{
    public static Loan CreateLoan(this LoanFactory factory)
    {
        return factory switch
        {
            LoanFactory.MORTGAGE => new MortgageLoan(),
            LoanFactory.PERSONAL => new PersonalLoan(),
            LoanFactory.AUTO => new AutoLoan(),
            _ => throw new ArgumentException("Invalid Loan Type")
        };
    }
}

// Client
public class BankingApplicationWithEnum
{
    public static void Main(string[] args)
    {
        Loan mortgageLoan = LoanFactory.MORTGAGE.CreateLoan();
        mortgageLoan.GetDetails();

        Loan personalLoan = LoanFactory.PERSONAL.CreateLoan();
        personalLoan.GetDetails();

        Loan autoLoan = LoanFactory.AUTO.CreateLoan();
        autoLoan.GetDetails();
    }
}

Key Points for Both Examples:

  1. Using Interfaces:

    • Provides a clean separation of concerns.
    • Adding new loan types requires creating new concrete product and factory classes.
  2. Using Enumerations:

    • Simplifies the logic by using a single enum to encapsulate all factory behavior.
    • Extensions on the enum provide centralized logic for creating different loan types.
    • Less flexible if individual factories or additional customization is required.

Both examples effectively demonstrate the Abstract Factory pattern in a C# context!

 

 

 

miércoles, 2 de mayo de 2018

Resilience Patterns common adv disadv

 

In software design, resilience patterns are strategies or techniques to ensure systems can recover gracefully and continue functioning despite failures, disruptions, or unexpected events. These patterns are especially relevant in distributed systems, cloud environments, and large-scale applications where failures are inevitable.

Here are common resilience patterns in software:


1. Retry Pattern

  • Description: Automatically retry a failed operation with a delay or exponential backoff to account for transient failures.
  • Use Case: Network timeouts, temporary unavailability of services.
  • Example:
    • A payment service retries a transaction after a brief pause if the upstream payment gateway fails to respond.
  • Tools: Libraries like Polly (C#), Resilience4j (Java).

2. Circuit Breaker Pattern

  • Description: Prevent repeated attempts to perform an operation that is likely to fail. When failures cross a threshold, the circuit "opens," blocking further calls for a cooldown period.
  • Use Case: Avoid cascading failures due to an unavailable or slow service.
  • Example:
    • If a database connection fails consistently, the application stops retrying for a set period and quickly responds with fallback logic.
  • Tools: Hystrix (Netflix), Resilience4j (Java), Polly (C#).

3. Fallback Pattern

  • Description: Provide an alternative response or behavior when an operation fails.
  • Use Case: Mitigating the impact of failure.
  • Example:
    • If a recommendation service fails, return static or cached recommendations instead.
  • Tools: Integrated into circuit breaker tools like Hystrix or Resilience4j.

4. Timeout Pattern

  • Description: Set a maximum duration for an operation to complete; if it exceeds that duration, abort the operation.
  • Use Case: Prevent a system from waiting indefinitely for a slow or unresponsive service.
  • Example:
    • An API call to a third-party service times out after 5 seconds, returning an error or fallback response.

5. Bulkhead Pattern

  • Description: Isolate critical components or resources into separate "pools" to prevent failure in one area from affecting others.
  • Use Case: Protect a system from resource exhaustion caused by a single failure.
  • Example:
    • If a particular service consumes too many threads or connections, it is isolated in its own thread pool to prevent affecting the entire application.
  • Tools: Thread pools, containerization (e.g., Kubernetes).

6. Rate Limiting and Throttling

  • Description: Limit the number of requests or operations that can occur in a given time period.
  • Use Case: Protect against excessive load, abuse, or denial-of-service attacks.
  • Example:
    • An API limits clients to 100 requests per minute to prevent server overload.
  • Tools: API Gateways, Redis (rate limiting), cloud-based tools like AWS API Gateway.

7. Idempotency Pattern

  • Description: Ensure that an operation can be performed multiple times without changing the result.
  • Use Case: Retry logic where multiple attempts may occur.
  • Example:
    • Retrying a payment request should not result in multiple charges.
  • Tools: Use unique identifiers (e.g., idempotency keys) to track operations.

8. Failover Pattern

  • Description: Switch to a backup system or component when the primary one fails.
  • Use Case: Ensure high availability and continuity.
  • Example:
    • If the primary database server fails, traffic is routed to a replica or standby database.
  • Tools: Load balancers, cloud failover mechanisms.

9. Data Replication Pattern

  • Description: Maintain copies of data across different nodes or regions to improve availability and resilience.
  • Use Case: Recover from hardware failures or data loss.
  • Example:
    • Data replication in distributed databases like Cassandra or PostgreSQL replicas.
  • Tools: Cloud databases (e.g., AWS RDS Multi-AZ), distributed storage (e.g., HDFS).

10. Chaos Engineering

  • Description: Introduce controlled failures to test and improve system resilience proactively.
  • Use Case: Validate a system’s ability to handle failures before they occur in production.
  • Example:
    • Simulating server failures or network latency using tools like Gremlin or Netflix Chaos Monkey.

11. Compensating Transaction Pattern

  • Description: Perform a rollback or corrective operation if a transaction across services fails.
  • Use Case: Ensuring consistency in distributed systems.
  • Example:
    • If booking a hotel succeeds but booking a flight fails, cancel the hotel reservation.

12. Message Queue and Event-Driven Architecture

  • Description: Use message queues to decouple services and ensure messages are retried or persisted during failures.
  • Use Case: Decouple systems to avoid cascading failures.
  • Example:
    • Using Kafka or RabbitMQ to persist messages during an outage and replay them later.

Why Use Resilience Patterns?

Resilience patterns are critical for:

  • Ensuring high availability in distributed systems.
  • Minimizing downtime caused by hardware, software, or network failures.
  • Improving user experience by handling failures gracefully.
  • Protecting system resources and preventing cascading failures.

By implementing these patterns, software systems can recover faster, adapt to transient issues, and continue delivering reliable performance even under adverse conditions.

 



Advantages and Disadvantages

Here’s a detailed explanation of the advantages and disadvantages of each resilience pattern:

 

1. Retry Pattern

  • Description: Automatically retry a failed operation after a delay or with an exponential backoff.

Advantages:

  • Simple to implement for transient failures like timeouts or temporary unavailability.
  • Improves reliability by overcoming temporary issues without user intervention.
  • Allows seamless recovery without manual intervention.

Disadvantages:

  • May cause overload if retries are not controlled (e.g., excessive retries can overwhelm a failing service).
  • Wastes resources when a failure is not transient (e.g., permanent failure cases).
  • Can cause longer delays if retries are too aggressive.

Best Use Case:

  • For transient failures (e.g., temporary network glitches, database deadlocks).

2. Circuit Breaker Pattern

  • Description: Stops repeated attempts to perform a failing operation. After failures reach a threshold, the circuit "opens" to block further calls temporarily.

Advantages:

  • Prevents cascading failures by quickly detecting and halting requests to faulty services.
  • Improves system stability under failure conditions.
  • Reduces unnecessary load on failing services.

Disadvantages:

  • Circuit recovery (from open to closed) can cause temporary "thundering herd" issues when many requests retry simultaneously.
  • Requires tuning thresholds and cooldown periods, which can be complex.
  • False positives may occur, causing healthy services to be temporarily blocked.

Best Use Case:

  • For dependent services that may fail or slow down, such as external APIs or databases.

3. Fallback Pattern

  • Description: Provides an alternative response or behavior when an operation fails.

Advantages:

  • Improves user experience by providing a degraded response instead of a failure.
  • Prevents complete system breakdown in case of failures.
  • Supports graceful degradation under partial failure scenarios.

Disadvantages:

  • Fallback logic might not always meet functional requirements (e.g., stale or inaccurate data).
  • Adds extra implementation effort to provide meaningful fallback mechanisms.
  • May mask underlying issues if fallback is used excessively.

Best Use Case:

  • When alternative data or cached responses can substitute for a failing service.

4. Timeout Pattern

  • Description: Sets a maximum time for an operation to complete, aborting it if it exceeds the limit.

Advantages:

  • Prevents the system from hanging indefinitely due to unresponsive components.
  • Frees up resources by abandoning slow operations.
  • Avoids cascading failures caused by blocked threads or connections.

Disadvantages:

  • Requires careful timeout tuning; too short may trigger false timeouts, too long may delay recovery.
  • May lead to incomplete operations or partial failures.
  • Combined with retries, it can increase load if not managed properly.

Best Use Case:

  • For network calls, database queries, or external service requests that might become unresponsive.

5. Bulkhead Pattern

  • Description: Isolates resources into separate pools to prevent one failure from impacting the entire system.

Advantages:

  • Limits the blast radius of a failure, ensuring other components remain unaffected.
  • Protects system stability by isolating resource-hungry services.
  • Useful for handling varying levels of load across services.

Disadvantages:

  • Resource isolation adds complexity (e.g., configuring multiple thread pools or containers).
  • May lead to underutilized resources if isolation is overprovisioned.
  • Incorrect configuration can still cause bottlenecks or resource exhaustion.

Best Use Case:

  • For resource-constrained systems with critical components that must remain unaffected by failures in others.

6. Rate Limiting and Throttling

  • Description: Limits the number of requests processed within a given time to prevent system overload.

Advantages:

  • Prevents overloading and potential denial of service.
  • Ensures fair usage of system resources.
  • Improves system stability during traffic spikes.

Disadvantages:

  • May block legitimate requests if limits are too strict.
  • Introduces additional latency for throttled requests.
  • Requires monitoring and dynamic configuration to adjust for varying loads.

Best Use Case:

  • For APIs or services with high load or risk of abuse.

7. Idempotency Pattern

  • Description: Ensures that an operation can be executed multiple times without side effects.

Advantages:

  • Safeguards against unintended duplicate operations caused by retries.
  • Ensures consistency in distributed systems.
  • Reduces the risk of data corruption or inconsistency.

Disadvantages:

  • Requires tracking of request states (e.g., using unique identifiers like idempotency keys).
  • Adds complexity to design and increases storage overhead.
  • Not all operations are naturally idempotent (e.g., payment processing).

Best Use Case:

  • For retry mechanisms where duplicates could cause issues (e.g., billing or payment APIs).

8. Failover Pattern

  • Description: Switches to a backup component or system when the primary one fails.

Advantages:

  • Ensures high availability and reduces downtime.
  • Provides seamless failover with minimal user impact.
  • Redundant systems improve fault tolerance.

Disadvantages:

  • Requires additional infrastructure and redundancy (increased cost).
  • Data synchronization between primary and backup can be challenging.
  • Failover mechanisms can introduce latency during switching.

Best Use Case:

  • For critical systems requiring high availability, such as databases or load-balanced services.

9. Data Replication Pattern

  • Description: Maintains copies of data across multiple nodes or regions.

Advantages:

  • Improves availability and resilience against hardware or node failures.
  • Enhances read performance by serving data from multiple locations.
  • Protects against data loss.

Disadvantages:

  • Increases data storage and synchronization costs.
  • May introduce eventual consistency issues in distributed systems.
  • Complex to manage across multiple nodes or regions.

Best Use Case:

  • For databases or distributed systems requiring fault tolerance and high availability.

10. Chaos Engineering

  • Description: Intentionally injects failures to test system resilience.

Advantages:

  • Proactively identifies weaknesses and improves fault tolerance.
  • Helps teams prepare for real-world failure scenarios.
  • Strengthens confidence in system resilience.

Disadvantages:

  • Requires careful planning to avoid unintended system disruptions.
  • Can cause real outages if experiments are not properly controlled.
  • Adds operational overhead for conducting and monitoring tests.

Best Use Case:

  • For large-scale systems where failures are inevitable, such as cloud-native applications.

11. Compensating Transaction Pattern

  • Description: Rolls back or corrects changes made by failed transactions.

Advantages:

  • Ensures data consistency across distributed systems.
  • Mitigates the impact of failures in multi-step workflows.
  • Supports "eventual consistency" in distributed systems.

Disadvantages:

  • Increases implementation complexity.
  • Requires careful design to handle rollback scenarios correctly.
  • May introduce latency when handling failures.

Best Use Case:

  • For distributed systems or microservices requiring transactional integrity.

12. Message Queue and Event-Driven Architecture

  • Description: Decouples services using message queues to persist and retry failed messages.

Advantages:

  • Increases system reliability by enabling asynchronous processing.
  • Ensures messages are not lost during failures.
  • Decouples systems to avoid cascading failures.

Disadvantages:

  • Adds latency compared to synchronous communication.
  • Requires infrastructure like message brokers (e.g., Kafka, RabbitMQ).
  • Potential message duplication or reordering must be handled.

Best Use Case:

  • For systems requiring asynchronous communication or retries, such as event-driven applications.

By carefully choosing the right resilience pattern for each failure scenario, systems can achieve high availability, stability, and reliability.

 

 

lunes, 2 de abril de 2018

Some of the most used and most common design patterns.

 

Here’s a list of the most used and most common design patterns, categorized by their type and popularity in software development:


1. Creational Patterns

Focus on object creation mechanisms, providing flexibility and efficiency.

  1. Singleton

    • Ensures a class has only one instance and provides a global point of access to it.

    • Commonly used for logging, configuration, and managing shared resources.

  2. Factory Method

    • Defines an interface for creating objects but lets subclasses decide which class to instantiate.

    • Commonly used in frameworks for creating objects without specifying exact classes.

  3. Abstract Factory

    • Provides an interface to create families of related or dependent objects without specifying their concrete classes.

    • Used in GUI libraries (e.g., different themes for UI components).

  4. Builder

    • Constructs complex objects step-by-step, separating the construction from representation.

    • Useful for creating immutable objects like StringBuilder or for object hierarchies.

  5. Prototype

    • Creates new objects by cloning an existing object (prototypes).

    • Used when object creation is costly, e.g., in game engines or document editors. 


       


2. Structural Patterns

Deal with composing classes or objects into larger structures while keeping them flexible and efficient.

  1. Adapter

    • Allows incompatible interfaces to work together by translating one interface to another.

    • Commonly used in legacy system integrations.

  2. Decorator

    • Adds functionality to an object dynamically without altering its structure.

    • Common in user interface components (e.g., adding scrollbars or borders).

  3. Facade

    • Provides a simplified interface to a complex subsystem.

    • Often used in APIs and libraries to hide implementation details.

  4. Composite

    • Composes objects into tree structures to represent part-whole hierarchies.

    • Frequently used in GUIs and file system representations.

  5. Proxy

    • Provides a surrogate or placeholder for another object to control access to it.

    • Used for lazy initialization, access control, and logging.

  6. Bridge

    • Decouples an abstraction from its implementation so that both can vary independently.

    • Common in graphical rendering libraries.

  7. Flyweight

    • Reduces memory usage by sharing as much data as possible with similar objects.

    • Used in caching mechanisms or text editors for character storage.


3. Behavioral Patterns

Concerned with the communication and interaction between objects.

  1. Strategy

    • Encapsulates algorithms and allows them to be interchangeable at runtime.

    • Common in payment processing systems and sorting algorithms.

  2. Observer

    • Defines a dependency between objects so that when one changes state, its dependents are notified.

    • Commonly used in event-driven programming and GUIs.

  3. Command

    • Encapsulates a request as an object, allowing parameterization and queuing of requests.

    • Used in undo/redo systems and job scheduling.

  4. State

    • Allows an object to change its behavior when its state changes.

    • Frequently used in workflows or state machines.

  5. Template Method

    • Defines the skeleton of an algorithm in a base class, allowing subclasses to override specific steps.

    • Common in frameworks and libraries.

  6. Chain of Responsibility

    • Passes a request along a chain of handlers until it is handled.

    • Used in logging systems or middleware pipelines.

  7. Mediator

    • Centralizes communication between objects to reduce dependencies.

    • Common in chat applications or GUIs.

  8. Iterator

    • Provides a way to access elements of a collection sequentially without exposing its underlying structure.

    • Used in collections and data structures.

  9. Visitor

    • Adds new operations to objects without modifying their classes.

    • Used in compilers or processing hierarchical structures.

  10. Memento

    • Captures an object’s state to restore it later.

    • Commonly used in undo functionality.


Additional Modern Patterns

Beyond the classical Gang of Four patterns, these modern patterns are also widely used:

  1. Dependency Injection (DI)

    • Provides dependencies to objects from an external source, improving modularity.

    • A cornerstone of frameworks like Spring or .NET Core.

  2. Model-View-Controller (MVC)

    • Separates an application into three components: Model (data), View (UI), and Controller (logic).

    • Dominant in web development frameworks like Ruby on Rails and ASP.NET MVC.

  3. Model-View-ViewModel (MVVM)

    • Variant of MVC, primarily used in UI frameworks like Angular or WPF.

  4. Repository

    • Abstracts access to data sources, providing a clean separation between the application and data layer.

    • Common in DDD (Domain-Driven Design).

  5. CQRS (Command Query Responsibility Segregation)

    • Separates read and write operations into different models.

    • Used in scalable architectures.

  6. Event Sourcing

    • Represents the state of an object as a sequence of events.

    • Common in microservices and systems requiring strong audit trails.


Most Used Patterns in Practice

  1. Singleton

  2. Factory Method

  3. Strategy

  4. Observer

  5. MVC/MVVM

  6. Dependency Injection

  7. Repository

  8. Adapter

  9. Decorator

  10. Command

These patterns are versatile, widely applicable, and form the backbone of most modern software systems.




domingo, 18 de septiembre de 2016

Los patrones de diseño más utilizados en el desarrollo de software

Están organizados en tres categorías principales según el libro "Design Patterns: Elements of Reusable Object-Oriented Software" (Gang of Four, GoF). A continuación, los patrones más usados dentro de cada categoría y algunos otros populares adicionales:


1. Creacionales

Estos patrones abordan la creación de objetos, asegurando que el sistema sea independiente de cómo se crean, componen y representan.

  1. Singleton

    • Garantiza que una clase tenga una única instancia y proporciona un punto de acceso global a ella.
  2. Factory Method

    • Define una interfaz para crear objetos, pero permite que las subclases decidan cuál clase instanciar.
  3. Abstract Factory

    • Proporciona una interfaz para crear familias de objetos relacionados o dependientes sin especificar sus clases concretas.
  4. Builder

    • Separa la construcción de un objeto complejo de su representación, permitiendo que el mismo proceso de construcción cree diferentes representaciones.
  5. Prototype

    • Permite clonar objetos existentes en lugar de crearlos desde cero, evitando el costo de inicialización compleja.

2. Estructurales

Estos patrones se ocupan de cómo componer clases y objetos para formar estructuras más grandes.

  1. Adapter

    • Permite que clases con interfaces incompatibles trabajen juntas mediante un "adaptador".
  2. Decorator

    • Añade funcionalidad adicional a un objeto de forma dinámica.
  3. Proxy

    • Proporciona un sustituto o marcador de posición para controlar el acceso a un objeto.
  4. Composite

    • Compone objetos en estructuras de árbol para representar jerarquías parte-todo, permitiendo que los clientes traten objetos individuales y compuestos de manera uniforme.
  5. Bridge

    • Desacopla una abstracción de su implementación para que ambas puedan variar de manera independiente.
  6. Facade

    • Proporciona una interfaz simplificada a un conjunto de interfaces en un subsistema.
  7. Flyweight

    • Reduce el costo de creación de objetos, reutilizando instancias existentes cuando es posible.

3. Comportamentales

Estos patrones se centran en la interacción y la responsabilidad entre objetos.

  1. Strategy

    • Define una familia de algoritmos, encapsula cada uno y los hace intercambiables.
  2. Observer

    • Permite que un objeto notifique a múltiples objetos interesados cuando cambia su estado.
  3. Command

    • Encapsula una solicitud como un objeto, permitiendo parametrizar clientes con diferentes solicitudes, hacer colas o registros de comandos, y soportar deshacer/rehacer.
  4. State

    • Permite que un objeto cambie su comportamiento cuando cambia su estado interno.
  5. Template Method

    • Define el esqueleto de un algoritmo en una operación, permitiendo que las subclases redefinan ciertos pasos sin cambiar la estructura general.
  6. Mediator

    • Descentraliza la comunicación entre objetos mediante un mediador.
  7. Chain of Responsibility

    • Permite que varios objetos manejen una solicitud, pasando la solicitud a lo largo de una cadena.
  8. Iterator

    • Proporciona una manera de acceder a los elementos de un objeto compuesto de forma secuencial sin exponer su representación subyacente.
  9. Visitor

    • Permite agregar nuevas operaciones a estructuras de objetos sin modificar sus clases.
  10. Memento

    • Captura y externaliza el estado interno de un objeto para poder restaurarlo más tarde.

Patrones Adicionales y Modernos

Además de los patrones clásicos de GoF, algunos patrones más modernos son ampliamente usados en el desarrollo de software:

  1. Dependency Injection (DI)

    • Permite inyectar dependencias en lugar de que un objeto las cree por sí mismo.
  2. Model-View-Controller (MVC)

    • Desglosa una aplicación en tres componentes principales: modelo, vista y controlador.
  3. Repository

    • Abstrae la lógica para acceder a datos de una base de datos o fuente externa.
  4. Unit of Work

    • Mantiene un registro de los cambios realizados a los datos para coordinar actualizaciones atómicas.
  5. Event Sourcing

    • Representa el estado de una entidad como una secuencia de eventos en lugar de un único estado.
  6. CQRS (Command Query Responsibility Segregation)

    • Separa las operaciones de lectura (query) de las operaciones de escritura (command) en diferentes modelos.

Estos patrones forman la base de muchas soluciones de software modernas y se eligen según las necesidades del problema y el contexto de la aplicación.

viernes, 18 de septiembre de 2015

CRUD con PHP5 OOP y Patron de Diseño MVC

Modelo-Vista-Controlador

MVC: es un patrón arquitectónico usado en ingeniería de software. Su uso exitoso aísla la lógica de negocio de las consideraciones de interfaz de usuario y la persistencia de la base de datos, lo que resulta en una aplicación donde es más fácil de modificar la apariencia visual de la aplicación o las reglas de negocio subyacentes sin afectar uno al otro. En MVC, el modelo representa la información (los datos por lo general pero no únicamente en RDBMS) de la solicitud; la vista se corresponde con los elementos de la interfaz de usuario (Preferiblemente independiente del dispositivo), tales como artículos de texto, casillas de verificación, y así sucesivamente; y el controlador gestiona la comunicación de los datos (o flujo del programa) y las reglas de negocio que se utilizan para manipular los datos hacia y desde el modelo. 



Modelo - representa el comportamiento de las aplicaciones y datos. También se conoce comúnmente como el dominio. El dominio representa el problema que está tratando de resolver. 

Vista - representa la presentación. Puede consultar el modelo de su estado y generar la presentación de los objetos del modelo. 

Controlador - representa aplicaciones de flujo de trabajo, que procesa los parámetros de la petición y decide qué hacer con base en ellos. Esto, por lo general, implica la manipulación del modelo y se presentan los datos en la vista seleccionada.


Ejemplo de una Aplicación CRUD


Para este taller de PHP en POO se ha creado un gestor de contactos simples que soporta las operaciones básicas CRUD. El usuario puede añadir un nuevo contacto, borrar, visualizar un detalle de contacto y visualización de la lista de todos los contactos. Me referiré a estas operaciones como las acciones. Por lo tanto, esta aplicación tiene cuatro acciones diferentes: Añadir un contacto, Eliminar un contacto, modificar un contacto y mostrar la lista de contactos. Adicionalmente y no forma parte explícitamente del CRUD, se puede ordenar los contactos. 


CRUD

Se conoce comúnmente por sus siglas en Ingles Create, Read, Update and Delete. Tiene varios acrónimos en Español.

Al pensar en el patrón MVC se puede ver un aspecto negativo y varios aspectos positivos. Lo negativo es que el patrón MVC introduce una complejidad en el proyecto que puede ser una carga para aplicaciones sencillas, pero a medida que crece su aplicación este aspecto negativo es más ponderado por los aspectos positivos. Voy a describir algunos aspectos positivos que se me ocurren.

MVC separa el modelo de la vista, es decir, los datos de su representación. La separación del modelo de la parte de presentación es una de las reglas básicas de un buen diseño de software. Cuando se separa un modelo de su presentación puede agregar fácilmente muchas presentaciones diferentes del mismo modelo. Por ejemplo, una aplicación web puede tener normalmente tiene presentación HTML, utilizado por los navegadores web, y la presentación JSON usado por los clientes JavaScript AJAX.

Un papel distintivo MVC nos permite distribuir mejor
los recursos humanos en un proyecto grande. Por ejemplo, los expertos de dominio y los expertos de base de datos pueden trabajar en un modelo mientras que los diseñadores web trabajan en una vista. Debido a que cada parte es desarrollado por los desarrolladores especializados, una aplicación puede ser de mejor calidad. Esto también afecta el tiempo de desarrollo, los proyectos se pueden construir más rápida ya que los desarrolladores especializados pueden trabajar simultáneamente, cada uno en su área de especialización, sin afectar (mucho) a otros desarrolladores que estén trabajando también.

Mantenimiento y las actualizaciones de una aplicación compleja son más fáciles debido a que un desarrollador puede mirar a la aplicación como una serie de "módulos" que consiste cada uno de Modelo, Vista y Controlador de la parte. Un desarrollador puede modificar uno "módulo" y no tiene que preocuparse de que los cambios que introdujo afectará a otras partes del sistema (creo que esto se llama separación de intereses). Además, al añadir nuevas funcionalidades a la aplicación, un desarrollador puede simplemente crear un nuevo "módulo".




La implementación


La aplicación consiste en el archivo index.php y varios archivos colocados en el modelo, vista y controlador de directorios:Estructura de programación orientada a objetos PHP MVC CRUD CarpetaEl script index.php es el punto de acceso central, todas las solicitudes pasan a través de él.El controlador se define en el directorio controlador:

     
ContactsController.phpLa vista de aplicación se definen en el directorio de vista:

    
contacto-form.php se encarga de mostrar "Añadir nuevo contacto" formulario para el usuario
    
contact.php se encarga de mostrar los datos de contacto a ser modificado.

    contacts.php se encarga de mostrar la lista de contactos.
   
error.php es responsable de mostrar errores.


El modelo

Antes de explicar el código fuente, debe saber algo sobre el modelo. El modelo tiene una sola entidad - Contacto que se persistió en la tabla de contactos. El contacto no tiene un comportamiento por lo que utiliza la estructura de tablas SQL para definirlo:

CREATE TABLE `contacts` (

    `id` int(11) NOT NULL AUTO_INCREMENT,

    `name` varchar(128) NOT NULL,

    `phone` varchar(64) DEFAULT NULL,

    `email` varchar(255) DEFAULT NULL,

    `address` varchar(255) DEFAULT NULL,

    PRIMARY KEY (`id`)

)

No hay ninguna clase en el modelo que representa la entidad de contacto, en vez utilicé objetos PHP estándar creadas automáticamente de la base de datos de registro. no es totalmente OO pero da una idea inicial para dar ejemplo a aquellos que se inician en la programación orientada a objetos y vienen de un pensamiento estructurado.

¿Qué podemos hacer con ese increíble modelo? Esta es la interfaz pública de la clase ContactsService donde se pueden ver todas las características del modelo:



ContactsService.php
  
ContactsService objeto no funciona con la base de datos directamente; En su lugar, utiliza el objeto ContactsGateway que a su vez emite consultas a la base de datos. Esta técnica se denomina tabla de datos de puerta de enlace existen otras técnicas.

La fuente


index.php
 
Este script tiene papel simple, se crea una instancia del objeto de controlador y se lo da el control de la aplicación mediante el método handleRequest.

Todas las solicitudes deben pasar por el script index.php porque MVC requiere que todas las peticiones son manejadas por el controlador que se llama desde el script index.php. Las aplicaciones web
MVC por lo general vuelven a redirigir todas las peticiones que pasan por el index.php que se puede hacer en la configuración del servidor.


ContactsController.php

El método handleRequest actúa como un Dispatcher de las acciones. El método decide qué acción debe tener que invocar basado en un valor del parámetro HTTP GET "op" e invoca el método que implementa la acción. Si alguna excepción desde los métodos de acción del método handleRequest los atrapa e imprime el mensaje de error. Por esto se le llama controlador base, por lo general eso lo hacen algunos frameworks y no tenemos que implementar esta función adicional al Controller, sino solo implementar en él la lógica de negocio.

En primer lugar, tenemos el método listContacts que tiene un flujo de trabajo sencillo, se lee un parámetro necesario para clasificar los contactos, los contactos se obtiene a partir del modelo ordenado, los almacena en la variable de contactos y, por último, incluye la vista.En segundo lugar, tenemos el método DeleteContact que se lee un identificador del contacto y le dice al modelo para eliminarlo. Por último, se redirige al usuario de vuelta al script index.php que a su vez invoca la acción de la lista de contactos. La acción de contactos de eliminación no puede funcionar sin el parámetro id, así, el método lanzará una excepción si el id de un contacto no está establecido.En tercer método es el método showContact que es similar al método DeleteContact usa un id para actualizar, así que no voy a perder el espacio explicarlo.Por último, el método saveContact muestra el formulario "Añadir nuevo contacto", o, procesa los datos que se transmiten de forma que si se presentó. Si cualquier ValidationException se produce en el modelo, los errores se recogen de la excepción y se pasan a la vista. Lo ideal sería que la vista debe mostrar (y de hecho lo hace).

contacts.php

La vista contacts.php, que es utilizado por la acción de la lista de contactos, requiere la variable de contactos para ser llenado con objetos de contacto. La variable se rellena con el método listContacts y se pasa a la vista con las normas de alcance PHP y entonces la vista utiliza los datos de él para mostrar los contactos como una tabla HTML.Scripts como el Scripts contacts.php se llaman plantillas o templates. Con un plantilla el desarrollador define una estructura fija que se llena con los valores de las variables de la aplicación (en tiempo de ejecución) y luego se presenta al usuario. Las plantillas contienen únicamente la lógica de presentación, debido a esto, estos Scripts son comprensibles por los no programadores (diseñadores, ...) lo que los hace muy útiles y se utiliza con frecuencia en aplicaciones web aplicando así una de las best practice, la segregación de tareas.
 

Github source code MCV CRUD

Se puede descargar el código en la siguiente dirección en Github.

https://github.com/ooleon/mvc-php-poo-crud-tutorial-001/blob/master/mvc_crud.zip


Gracias.