De script a producte
Hi havia un script de 200 línies. Funcionava. Aquí no acabava la història — sense la passa següent, no hi hauria família.
Hi havia un script. Dos-centes línies. Funcionava. Aquí no s’acabava la història — sense la passa següent, Lumware no seria una família.
El context
El primer host era un main.py de dues-centes línies. Obria
un fitxer, calculava colors per a cada LED, escrivia per
serial. Sense tests. Sense logs estructurats. Sense
separació entre llegir, transformar i enviar.
Funcionava perquè tot estava al cap d’una persona — la meva. El dia que vaig deixar-ho un mes i el vaig tornar a obrir, vaig haver de tornar a entendre què feia. La segona setmana hi vaig afegir una “petita millora” i va deixar de funcionar. Cap test em va avisar perquè no n’hi havia cap.
L’opció fàcil: arreglar la regressió i seguir. L’opció real: parar i tractar-ho com a producte.
La decisió
Tres canvis simultanis, no negociables:
1. Estructura modular. El paquet lumware/scripts/
deixa de ser un fitxer i passa a ser cinc àrees amb fronteres
clares:
core/— events, settings, scheduler, cache, colors.protocol/— codec binari, CRC, definicions de frame.transport/— sèrie real i loopback per a tests.importers/— imatges i vídeos a frames RGB.server/— FastAPI + WebSocket per a la UI web.
Plus cli/ (la capa Unity-stdin) i orchestrator.py
(playback en thread propi).
2. Tests reals. No demos. No assertions a if __name__.
Tres nivells: unit a core/, integration a server/ i
orchestrator/, compat per al contracte Unity stdin. Floor
de cobertura del 80 % a core/, ancorada al pyproject.toml
(avui rodant pel 98 %).
3. Convencions explícites. Imports relatius dins del
paquet. print() prohibit al core (només EventBus).
time.perf_counter sempre per al scheduler — mai
time.time(). Settings immutables. tools/ queda al
marge: pot fer shell=True, però res del runtime n’importa.
Per què aquestes regles i no altres. Cada regla està ancorada a una raó concreta: el
print()prohibit ve del contracte Unity (la UI espera events serialitzats); elperf_counterve d’un bug real de derives amb wall-clock a l’antic codi; les Settings frozen vénen de no fiar-se de mutacions creuades quan el playback i la UI corren a threads diferents. Elruff.extend-excludeestà comentat alpyproject.tomlamb la story que retira cada exclusió, així els legacy paths no s’eternitzen.
Aquest pas no inventa res nou. Pren el que ja funcionava i el reorganitza al voltant de fronteres ben definides. Però és el que fa possibles Lumware Capture i Lumware Stage — comparteixen vocabulari (frames, transport, host, codec) perquè aquest vocabulari, aquí, té un significat explícit i contrastable.
El que ve
Al pròxim post baixem al nivell físic: tira NeoPixel, font d’alimentació, level shifter, terra comú. Sis components i el motiu real de cadascun — perquè el software pot ser perfecte i el primer LED encara fer-te color random si la massa no està compartida.