CAPÍTULO 3 · Cada pieza encuentra su responsabilidad
Las herramientas pequeñas también merecen un lugar
No todo el trabajo de SensorHub consiste en leer o guardar objetos. Una temperatura puede necesitar conversión y una medición puede pasar por un cálculo que también utiliza un reporte. Si esas operaciones quedan dentro de una vista, reutilizarlas obliga a importar piezas HTTP que no aportan nada al cálculo.
Reunimos esas funciones en UTIL_LIB y cuidamos que sus entradas y salidas expresen unidades y límites. Una función pura permite probar un resultado sin levantar el servidor ni preparar una base. Su utilidad no depende de que la invoque una query, un command o una tarea. La biblioteca de utilidades y repoGenerico resuelven así repeticiones de naturaleza diferente.
Ya podemos distinguir configuración, datos, transporte, servicios y herramientas. Esa estructura ayuda a quien desarrolla el backend, pero todavía falta llevarla al lugar donde una persona usa la plataforma. Las vistas que presentan pantallas también van a compartir comportamiento, y necesitamos componerlo sin volver a copiar bloques enteros.
Leer esta parte dentro del relato completo →DEL RELATO A LA PRÁCTICA
Vamos a desarrollar esta decisión con su mapa, explicación, código y ejercicio.
MIRA · CONECTA · COMPRENDE
Una herramienta con entrada y salida
Las flechas resumen el recorrido conceptual. Los controles y dependencias se detallan debajo.
Selecciona una pieza para destacar su responsabilidad.
Leer la explicación del mapa
- Valor. Incluye unidad de entrada
- Validación. Comprueba rango y tipo
- Función pura. Transforma sin efectos externos
- Resultado. Expresa la unidad destino
01 / EL PROBLEMA
¿Para qué sirve?
Convertir una temperatura en cada endpoint puede introducir diferencias entre el gráfico y el CSV. Una función compartida expresa la fórmula y su contrato.
02 / COMPRENDER
El concepto, explicado
Una función pura recibe entradas y retorna un resultado sin modificar estado externo. Eso facilita pruebas y reutilización.
Las unidades forman parte del tipo conceptual del dato. Documenta origen, salida y límites; no confundas cero con ausencia ni admitas NaN sin una política.
03 / CONSTRUIR
Implementación paso a paso
- Declara unidades en nombres o docstrings.
- Valida límites en la frontera.
- Mantén la fórmula independiente de request.
- Usa referencias y tolerancias apropiadas.
04 / APLICAR
Ejemplo en SensorHub
# UTIL_LIB/conversiones.py
def celsius_a_fahrenheit(celsius):
"""Recibe °C y devuelve °F; la entrada debe ser un número finito."""
return celsius * 9 / 5 + 32
# Pruebas de referencia
assert celsius_a_fahrenheit(0) == 32
assert celsius_a_fahrenheit(100) == 212
assert celsius_a_fahrenheit(-40) == -40Cómo leer el ejemplo
- La validación del endpoint debe rechazar no finitos y entradas físicamente inválidas.
- La función puede usarse desde CSV, websocket o un script.
- Usa is not None para distinguir una medida cero de un dato ausente.
Prueba la función con Django
El navegador llama al endpoint público, que valida entrada y usa UTIL_LIB. No guarda mediciones.
Error habitual
No uses if temperatura para comprobar existencia: rechazaría 0 °C, una medida válida.
05 / PRACTICAR
Tu turno
Ejecuta el laboratorio de esta lección con cero y con -274 °C.
Ver solución orientativa
Cero produce 32 °F; -274 °C se rechaza por estar por debajo del cero absoluto.
06 / VERIFICAR
Cómo sabes que funciona
- La misma entrada da la misma salida en todas las superficies.
- Los casos cero y ausencia tienen comportamiento distinto.
CONTINUAR LA EXPERIENCIA
El siguiente paso del recorrido:
Mixins, MRO y super() →Continuar en modo relato