166 lecturas

Refactoring 029 - Cómo reemplazar NULL con la colección

por Maximiliano Contieri6m2025/06/02
Read on Terminal Reader

Demasiado Largo; Para Leer

Reemplazar los atributos opcionales anulables con colecciones vacías para eliminar los controles nulos y aprovechar el polimorfismo.
featured image - Refactoring 029 - Cómo reemplazar NULL con la colección
Maximiliano Contieri HackerNoon profile picture

Transformar los atributos opcionales en colecciones vacías para un código más limpio, más seguro y polimórfico, eliminando el error de miles de millones de dólares

TL;DR: Replace nullable optional attributes with empty collections to eliminate null checks and leverage polymorphism.

TL;DR: Replace nullable optional attributes with empty collections to eliminate null checks and leverage polymorphism.

Problemas solucionados

  • Nulls reference exceptions
  • Excessive conditional logic and IFs
  • Fragile error handling
  • Atributos opcionales
  • Complex validation code
  • Violencia del polimorfismo

Pasos

  1. Identify nullable optional attributes that could be collections
  2. Replace single nullable objects with empty collections
  3. Remove all null checks related to these optional attributes
  4. Update methods to work with collections instead of single objects

Código de muestreo

Before 🚨

public class ShoppingCart {
    private List<Item> items = new ArrayList<>();
    private Coupon coupon = null;
    
    public void addItem(Item item) {
        this.items.add(item);
    }
    
    public void redeemCoupon(Coupon coupon) {
        this.coupon = coupon;
    }
    
    public double total() {
        double total = 0;
        
        for (Item item : this.items) {
            total += item.getPrice();
        }
        
        // This a polluted IF and null check
        if (this.coupon != null) {
            total -= this.coupon.getDiscount();
        }
        
        return total;
    }
    
    public boolean hasUnsavedChanges() {
        // Explicit null check
        return !this.items.isEmpty() || this.coupon != null;
    }
    
    public boolean hasCoupon() {        
        return this.coupon != null;
    }
}
public class ShoppingCart {
    private final List<Item> items = new ArrayList<>();
  
    // This version uses Optionals
    // Not all programming languages support this feature
    private Optional<Coupon> coupon = Optional.empty();

    public void addItem(Item item) {
        items.add(item);
    }

    public void redeemCoupon(Coupon coupon) {
        // You need to understand how optionals work
        this.coupon = Optional.ofNullable(coupon);
    }
    
    public boolean hasUnsavedChanges() {
        return !items.isEmpty() || !coupon.isPresent();
    }

    public boolean hasCoupon() {
        return coupon.isPresent();
    }
}

Después de 🙂

public class ShoppingCart {
  private List<Item> items = new ArrayList<>();
    
  // 1. Identify nullable optional attributes
  // that could be collections
  // 2. Replace single nullable objects with empty collections
  private List<Coupon> coupons = new ArrayList<>();
    
  public void addItem(Item item) {
      this.items.add(item);
  }
    
  // Step 4: Work with collection
  // instead of single nullable object
  public void redeemCoupon(Coupon coupon) {
      this.coupons.add(coupon);
  }
    
  // Step 4: Simplified logic without null checks
  public double total() {
    double total = 0;
      
    for (Item item : this.items) {
        total += item.getPrice();
    }
      
    // 3. Remove all null checks 
    // related to these optional attributes        
    for (Coupon coupon : this.coupons) {
        total -= coupon.getDiscount();
    }
      
    return total;
  }
    
  // Consistent behavior with empty collections
  public boolean hasUnsavedChanges() {
    // 4. Update methods to work with collections
    // instead of single objects 
    return !this.items.isEmpty() || !this.coupons.isEmpty();
  }
    
  // 3. Remove all null checks 
  // related to these optional attributes
  // Collection-based check instead of null check
  public boolean hasCoupon() {
    return !this.coupons.isEmpty();
  }
}

Type 📝

  • [x]Semi-Automatic

Safety 🛡️

This refactoring is generally safe when you control all access points to the collection attributes.


You need to ensure that no external code expects null values and deal with the inside APIs.


The refactoring maintains the same external behavior while simplifying internal logic.


You should verify that all constructors and factory methods initialize collections properly.

Why is the Code Better? ✨

The refactored code eliminates null pointer exceptions and reduces conditional complexity.


Empty collections and non-empty collections behave polymorphically, allowing you to treat them uniformly.


The code becomes more predictable since collections always exist (at least empty) and respond to the same operations.


Las implementaciones de métodos se vuelven más cortas y se centran más en la lógica de negocio en lugar del manejo nulo.


El enfoque se alinea con el principio de hacer que los estados ilegales no sean representados en su modelo de dominio, lo que lleva a un código más robusto y mantenible.


Colecciones vacías y colecciones no vacíaspolymorphic.

How Does it Improve the Bijection? 🗺️

En el mundo real, los contenedores existen incluso cuando están vacíos.


By representing optional collections as empty collections rather than null, you create a more accurate model of reality.


nulo no existe en el mundo real, y siempre rompe elbijection.


Esto mantiene la correspondencia uno a uno entre los conceptos del mundo real y su modelo computacional, creando una buenaMapa.


When you return a collection instead of nulls, you also reduce the coupling.

Limitations ⚠️

This refactoring may not be suitable when null has a semantic meaning different from "empty". Some legacy APIs might expect null values, requiring adaptation layers.


Debe asegurarse de que todos los caminos de código inicialicen las colecciones de manera consistente para evitar estados nulos y vacíos mixtos.

Refactor With AI 🤖

Prompt sugerido: 1. Identificar los atributos opcionales resueltos que podrían ser colecciones 2. reemplazar los objetos individuales resueltos por colecciones vacías 3. eliminar todos los controles nulos relacionados con estos atributos opcionales 4. actualizar los métodos para trabajar con colecciones en lugar de objetos individuales 5.

Prompt sugerido: 1. Identificar los atributos opcionales resueltos que podrían ser colecciones 2. reemplazar los objetos individuales resueltos por colecciones vacías 3. eliminar todos los controles nulos relacionados con estos atributos opcionales 4. actualizar los métodos para trabajar con colecciones en lugar de objetos individuales 5.

Without Proper Instructions

With Specific Instructions

ChatGPT

ChatGPT

Claude

Claude

Perplexity

Perplexity

Copilot

Copilot

Gemini

Gemini

DeepSeek

DeepSeek

Meta AI

Meta AI

Grok

Grok

Qwen

Qwen

ChatGPT

ChatGPT

Claude

Claude

Perplexity

Perplejidad

Copilot

Copilot

Gemini

Gemini

DeepSeek

DeepSeek

Meta AI

Meta AI

Grok

Grúas

Quien

Qwen

Tags 🏷️

  • Null

Level 🔋

  • [x]Intermediate

Es decir,

Credits 🙏

Image by En el k. on Pixabay


This article is part of the Refactoring Series.


Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks