Hacer cadenas inteligentes en Python

Jan 10 2023
Aplicar el diseño dirigido por el dominio
Las buenas ideas arquitectónicas no son solo para proyectos grandes y complicados. Tanto si ha oído hablar del diseño basado en dominios como si no, le mostraré cómo mejorar su proyecto, grande o pequeño, aplicando los principios básicos a las cadenas que ha estado pasando.
Foto de xandtor en Unsplash

Las buenas ideas arquitectónicas no son solo para proyectos grandes y complicados. Tanto si ha oído hablar del diseño basado en dominios como si no, le mostraré cómo mejorar su proyecto, grande o pequeño, aplicando los principios básicos a las cadenas que ha estado pasando. Es hora de recolectar esos fragmentos perdidos de código de validación y análisis que ha esparcido por todos lados y colocarlos en una unidad agradable y reutilizable.

Vamos a rascar la superficie del diseño basado en dominios aquí. Querrá obtener una copia del libro del mismo nombre de Eric Evans al final de este artículo. El concepto central es que su modelo de objetos se desarrolla mejor utilizando el lenguaje del dominio empresarial. Las reglas de negocio están codificadas en el modelo. Esto se mantiene separado del código de aplicación e infraestructura. Vamos a ceñirnos a un ejemplo simple de cómo puede aplicar esta idea a cadenas en su código.

Descubrí que las cadenas son un objetivo simple para empezar y si eso es todo lo que haces, disfrutarás de los beneficios. Hoy en día, tenemos un método para obtener la ubicación de la terminal de un vuelo a partir de su número de vuelo, como LA8165. Podemos tratar el número de vuelo como una cadena:

def getTerminal(flight_number): 
  return db.getTerminal(flight_number)

def getTerminal(flight_number): 
  # Normalize input to a clean string
  flight_number = str(flight_number).upper().strip()
  if not flight_number:
    raise ValueError(“Flight Number can not be empty.”)

  return db.getTerminal(flight_number)

class FlightNumber(object):
  def __init__(self, flight_number):
    # Normalize input to a clean string
    flight_number = str(flight_number).upper().strip()
    if not flight_number:
      raise ValueError(“Flight Number can not be empty.”)
    self.flight_number = flight_number

  # The value when this is cast to a string or used in a formatted string
  def __str__(self):
    return self.flight_number

def getTerminal(flight_number): 
  flight_number = FlightNumber(flight_number)
  return db.getTerminal(str(flight_number))

Ahora exploraremos todos los beneficios sutiles de esta forma de pensar:

  1. Nuestra nueva clase es increíblemente fácil de probar porque no toca sistemas de archivos o redes ni nada de lo que necesitemos simular.
  2. Disponemos de un único lugar para añadir documentación.
  3. Podemos empaquetar esto con todas las reglas y el análisis que queramos para completarlo.
  4. Cualquier persona nueva en el proyecto aprenderá fácilmente qué es un número de vuelo, muy específicamente.
  5. Todos estos objetos pueden ir en una carpeta de dominio para que sean reutilizables y detectables.
  6. El código de llamada es más fácil de leer y las solicitudes de extracción son más simples.
  7. Los errores se detectarán antes en la pila

class FlightNumber(object):
  """
  Represents an International Air Transport Association flight number. Ex — LA8165
  The format is two uppercase letters for the airline followed by up to four digits. 
  """
  def __init__(self, flight_number):
  # Normalize input to a clean string
  flight_number = str(flight_number).upper().strip()
  if not flight_number:
    raise ValueError("Flight Number can not be empty.")
  self.airline_code = flight_number[0:2].strip()
  if not self.airline_code.isalpha():
    raise ValueError(f"Airline Code {self.airline_code} must be two letters.")
  # Throws ValueError already if not a valid int
  self.numeric_part = int(flight_number[2:])
  if self.numeric_part < 1 or self.numeric_part > 9999:
    raise ValueError(f”Flight Number {self.numeric_part} must be from 1 to 9999.”)
  if self.numeric_part == 666:
    raise ValueError(f"Seriously, airlines don’t use this flight number.")

  def __str__(self):
    return f"{self.airline_code}{self.numeric_part}"

Referencias

  • Diseño basado en dominios