153 lecturas

Código Olor 304: Excepción de indicador nulo - Cómo evitar las referencias NULL que causan accidentes de tiempo de ejecución

por Maximiliano Contieri9m2025/06/20
Read on Terminal Reader

Demasiado Largo; Para Leer

Evite las referencias NULL que causan fallos de tiempo de ejecución utilizando la validación adecuada y los patrones de seguridad nula
featured image - Código Olor 304: Excepción de indicador nulo - Cómo evitar las referencias NULL que causan accidentes de tiempo de ejecución
Maximiliano Contieri HackerNoon profile picture

Sigo escribiendo sobre los problemas de NULL, pero todos los días las noticias me recuerdan: NULL todavía está vivo y golpeando.


TL;DR: Evite las referencias NULL que causan fallos de tiempo de ejecución mediante el uso de patrones de validación adecuados y de seguridad nula

TL;DR: Evite las referencias NULL que causan fallos de tiempo de ejecución mediante el uso de patrones de validación adecuados y de seguridad nula

Problemas

  • Crisis de Runtime
  • Incidentes y interrupciones importantes
  • Comportamiento impredecible
  • Debugging duro
  • Frustración del usuario
  • Inestabilidad del sistema
  • Poca fiabilidad

enGoogle CloudEl caso:

  • Gestión de error pobre: el código se estrelló en lugar de manejar graciosamente los datos nulos
  • No hay banderas de características: el nuevo código no se introdujo gradualmente con los controles de seguridad
  • Replicación global instantánea: los datos malos se propagan en todo el mundo de inmediato como en el Incidente de Crowdstrike
  • No hay retroceso aleatorio: la recuperación causó sobrecarga de infraestructuras
  • Test inadecuado: el escenario de fallo nunca fue probado durante el despliegue

Soluciones

  1. Evitar los nulos
  2. Utilice verificaciones null si las nulls están fuera de su control (por ejemplo, una API externa)
  3. Inicializar los valores por defecto
  4. Implementación de cláusulas de guardia
  5. Uso de objetos nulos
  6. No utilices opciones

Recuperación ️

https://hackernoon.com/code-refactoring-tips-no-015-remove-null

Contexto

El 12 de junio de 2025, aGran interrupciónEsto ocurrió en Google Cloud Platform.


Afectó a decenas de servicios de Google Cloud y Google Workspace en todo el mundo desde aproximadamente las 10:49 AM hasta las 1:49 PM PDT (3 horas en total), con algunos servicios que tardan más tiempo en recuperarse por completo.


La interrupción fue causada por un fallo en cascada en el sistema de gestión de API de Google:


  • En el trigger:

El 29 de mayo de 2025, Google implementó un nuevo código en "Service Control" (su sistema de gestión de API) que añadió controles adicionales de la política de cuotas.


Este código tenía un defecto crítico. Faltaba el correctoAcción erróneaNo estaba protegido porFicha de banderas.


  • El fracaso :

El 12 de junio, un cambio de política que contiene blanco/ceroLos campos fueron empujados a la base de datos global que utiliza Service Control.Cuando Service Control intentó procesar estos campos vacíos, se encontró con un puntero nulo en el camino de código no protegido, lo que resultó en que los binarios se colapsaron en un ciclo infinito.


  • Impacto global :

Dado que la gestión de las cuotas es global, estos datos corruptos se replicaron en todo el mundo en segundos, causando que el Control de Servicios se estrellara en todas las regiones.


Las excepciones de indicador nulo ocurren cuando intenta acceder a métodos o propiedades en objetos que no existen.


Esto ocurre cuando las variables contienen referencias null en lugar de instancias de objeto válidas.


El problema se vuelve particularmente peligroso en entornos de producción donde estas excepciones pueden colapsar su aplicación y frustrar a los usuarios.


Lenguajes como Java, C# y JavaScript son especialmente propensos a este problema, aunque las características y patrones de lenguaje modernos pueden ayudarle a evitar estos accidentes por completo.


Los nulls han sido un problema significativo en la industria del software durante décadas, pero los ingenieros de software siguen ignorándolos a pesar de las advertencias de su creador.

Código de muestreo

equivocado 🙂

public class ServiceControlPolicy {
  private SpannerDatabase spannerDB;
  private QuotaManager quotaManager;
    
  public void applyPolicyChange(PolicyChange change) {
      // NULL POINTER: change can be null
      Policy policy = spannerDB.getPolicy(change.getPolicyId());
      // NULL POINTER: policy can be null from the database
      String quotaField = policy.getQuotaField();
      // NULL POINTER: quotaField can be null (blank field)
      quotaManager.updateQuota(quotaField, change.getValue());
  }
    
  public void exerciseQuotaChecks(String region) {
      // NULL POINTER: policies list can be null
      List<Policy> policies = spannerDB.getPoliciesForRegion(region);
      for (Policy policy : policies) {
          // NULL POINTER: individual policy can be null
          String quotaValue = policy.getQuotaField();
          // NULL POINTER: quotaValue can be null before trim()
          quotaManager.checkQuota(quotaValue.trim());
      }
  }
    
  public boolean validatePolicyData(Policy policy) {
      // NULL POINTER: policy parameter can be null
      String quotaField = policy.getQuotaField();
      // NULL POINTER: quotaField can be null before length()
      return quotaField.length() > 0 && 
             !quotaField.equals("null");
  }
    
  public void replicateGlobally(PolicyChange change) {
      List<String> regions = getGlobalRegions();
      for (String region : regions) {
          // NULL POINTER: change.getPolicy() can return null
          spannerDB.insertPolicy(region, change.getPolicy());
      }
  }
}

Derecho

public class ServiceControlPolicy {
  private SpannerDatabase spannerDB;
  private QuotaManager quotaManager;
    
  public void applyPolicyChange(PolicyChange change) {
      if (change == null) {
          // Assuming it comes from an external API
          // Beyond your control
          change = new NullPolicyChange();
      }
      
      Policy policy = findPolicyOrNull(change.policyId());
      String quotaField = policy.quotaField();
      if (!quotaField.isEmpty()) {
          quotaManager.updateQuota(quotaField, change.value());
      }
  }
    
  public void exerciseQuotaChecks(String region) {
      if (region == null || region.isEmpty()) {
          // Assuming it comes from an external API
          // Beyond your control
          return;
      }
      
      List<Policy> policies = policiesOrEmpty(region);
      
      for (Policy policy : policies) {
          String quotaValue = policy.quotaField();
          if (!quotaValue.isEmpty()) {
              quotaManager.checkQuota(quotaValue.trim());
          }
      }
  }
    
  public boolean validatePolicyData(Policy policy) {
      if (policy == null) {
          // Assuming it comes from an external API
          // Beyond your control
          // From now on, you wrap it
          policy = new NullPolicy();
      }
      
      String quotaField = policy.quotaField();
      return quotaField.length() > 0;
  }
    
  public void replicateGlobally(PolicyChange change) {
      if (change == null) {
          // Assuming it comes from an external API
          // Beyond your control
          // From now on, you wrap it
          change = new NullPolicyChange();
      }
        
      Policy policy = change.policy();
      if (policy == null) {
          // Assuming it comes from an external API
          // Beyond your control
          // From now on, you wrap it
          policy = new NullPolicy();
      }
        
      List<String> regions = globalRegions();
      for (String region : regions) {
          spannerDB.insertPolicy(region, policy);
      }
  }
    
  private Policy findPolicyOrNull(String policyId) {
      Policy policy = spannerDB.policy(policyId);
      return policy != null ? policy : new NullPolicy();
  }
    
  private List<Policy> policiesOrEmpty(String region) {
      List<Policy> policies = spannerDB.policiesForRegion(region);
      if (policies == null) {
          // This is a good NullObject
          return Collections.emptyList();
      }
      
      return policies.stream()
              .map(p -> p != null ? p : new NullPolicy())
              .collect(Collectors.toList());
  }
}

class NullPolicy extends Policy {
  @Override
  public String quotaField() { return ""; }
    
  @Override
  public String policyId() { return "unknown-policy"; }
    
  @Override
  public Map<String, String> metadata() { 
      return Collections.emptyMap(); 
  }
}

class NullPolicyChange extends PolicyChange {
  @Override
  public String policyId() { return ""; }
    
  @Override
  public String value() { return ""; }
    
  @Override
  public Policy policy() { return new NullPolicy(); }
}

Detección

  • [x] Semi-automático

Puede detectar posibles excepciones de indicador nulo revisando el código para llamadas de método directo en objetos sin verificaciones nulas.


Los Linters pueden examinar los valores de retorno de los métodos que podríancero, buscando campos de objeto no inicializados, y utilizando herramientas de análisis estático que señalan potenciales dereferencias nulas.


Las IDE modernas a menudo destacan estos problemas con advertencias.

Tags ️

  • cero

Nivel

  • [x] El Intermedio

¿Por qué es importante la bijeción ️

En laEl mundo realLos objetos o existen o no existen.


Cuando modelas esto correctamente en tu programa, creas un claroCorrespondencia de uno a unoentre la realidad y el código.


Romper esta bijeción permitiendo referencias nulas crea objetos fantasmas que existen en su código pero no en el mundo real, lo que lleva a colisiones cuando intenta interactuar con estas entidades no existentes.


Si elige nombrar su placa de licencia "NULL", obtendráMuchas entradas de aparcamiento

La generación

Los generadores de IA a menudo crean código con vulnerabilidades de puntero nulo porque se centran en escenarios de camino feliz.


A menudo generan llamadas de método sin considerar casos de borde donde los objetos podrían estarcero, especialmente en jerarquías de objetos complejos o cuando se trata de fuentes de datos externas.

Detección

Las herramientas de IA pueden detectar y corregir problemas de puntero nulo cuando proporciona instrucciones claras sobre prácticas de programación defensiva.

¡Pruébelo!

Recuerda: los asistentes de IA cometen muchos errores

Prompt sugerido: Eliminar todas las referencias nulas

Prompt sugerido: Eliminar todas las referencias nulas

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

Perplejidad

Perplejidad

piloto

piloto

Gemini

Gemini

profundidad

profundidad

El objetivo es

El objetivo es

Grúas

Grúas

Quien

Quien

Conclusión

Las excepciones de puntero nulo representan uno de los errores de tiempo de ejecución más comunes en la programación.


Puede eliminar la mayoría de estos accidentes mediante la implementación de verificaciones nulas adecuadas, utilizando el patrón de diseño de Objeto Nulo y adoptando prácticas de programación defensiva.


La pequeña cantidad de código de validación se paga significativamente en la estabilidad de la aplicación y la experiencia del usuario.

Relaciones

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-iii-t7h3zkv

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xliii

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxxix

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxvi

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xlii

Más información

Disclaimer

Los olores son míosOpinión.


Lo llamo mi error de miles de millones de dólares.Fue la invención de la referencia nula en 1965.

Lo llamo mi error de miles de millones de dólares.Fue la invención de la referencia nula en 1965.

de Tony Hoare


Este artículo es parte de la serie CodeSmell.


Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks