Hace tiempo leí un
artículo titulado “The Growing Importance of Sustaining Software for de Dod” de
Doug Schmidt’s blog. Doug hice la siguiente afirmación:
“Aunque el software no
se desgasta, el firmware y el hardware se convierte en obsoleto y por lo tanto
requiere de modificaciones software.”
Este fue un momento un
momento esclarecedor para mi. Doug mencionó dos términos que yo habría pensado
que eran obvios pero no. Software es esa cosa que puede tener una vida útil
pero firmware se convertirá en obsoleto a medida que evolucione el hardware. Si
has gastado algo de tiempo en desarrollo de sistemas embebidos, sabes que el
hardware está continuamente evolucionando y mejorando. Al mismo tiempo, las
características que se añadieron al nuevo software y este crece continuamente
en complejidad.
Me gustaría añadir a la
frase de Doug:
“Aunque el software no
se desgasta, este se puede destruir desde el interior por dependencias no
administradas del firmware y el hardware.”
No es raro que al
software embebido se le niegue una vida potencialmente larga debido a estar
infectado con dependencias del hardware.
Me gusta la definición
de Doug del firmware, pero hay que ver otras definiciones:
- Firmware
se mantiene en dispositivos de memorías no volátiles como ROM, EPROM o
memorías flash.(https://en.wikipedia.org/wiki/Firmware)
- Firmware
es un programa software o un conjunto de instrucciones programadas en un
dispositivo hardware.(https://techterms.com/definition/firmware)
- Firmware
es software que está incrustado en una pieza de hardware.(https://www.lifewire.com/what-is-firmware-2625881)
- Firmware
es “Software (programas o datos) que se han escrito en memoria de solo
lectura (ROM).(http://www.webopedia.com/TERM/F/firmware.html)
La definición de Doug me
hace darme cuenta que estas definiciones de firmware están mal o al menos están
obsoletas. Firmware no significa que el código vive en un ROM. No es firmware
por donde esté almacenado, más que eso, es firmware porque de lo que depende y
de cómo de difícil es de cambiar a medida de cómo evoluciona el hardware. El
hardware evoluciona así que estructuraríamos nuestro código embebido con esa
realidad en mente.
No tengo nada contra el
firmware o lo ingenieros firmware pero lo que se necesita es menos firmware y
más software. Actualmente estoy en desacuerdo de que los ingenieros de firmware
escriban tanto firmware.
Los ingenieros no
firmware también escriben firmware! Los desarrolladores no firmware escriben
esencialmente firmware cuando entierran una consulta SQL en el código o cuando
difunden dependencias de la plataforma por todo su código. Los desarrolladores
de Android escriben firmware cuando ellos no separan su lógica de negocio de la
API de Android.
He estado involucrado en
mucho esfuerzo donde la línea entre el código del producto (el software) y el
código que interactúa con el hardware del producto (el firmware) es confuso
hasta el punto de no existir. Por ejemplo, al final de los 90 tuve la diversión
de ayudar a rediseñar un subsistema de comunicaciones que estaba en transición
de time division multiplexing (TDM) a voice over IP (VOIP). VOIP es como se hacen
las cosas ahora pero TDM fue considera estado del arte desde los 50 hasta los
60 y se desarrolló ampliamente en los 80 y 90.
En cualquier momento que
teníamos una pregunta para el ingenieros de sistemas sobre como una llamada
debería reaccionar a una situación dada, él desaparecería y un poco más tarde
vendría con una respuesta detallada. ¿De dónde sacó la respuesta? La respuesta
del ingeniero fue: “del código.” O sea, que el código enredado ¡fue la
especificación para el nuevo producto! La implementación existente no tenía
separación entre TDM y la lógica de negocio de hacer llamadas. Todo el producto
fue hardware/tecnológicamente dependiente de arriba a abajo y no se podía
desenredar. Todo el producto se había convertido esencialmente en firmware.
Considera otro ejemplo:
Los mensajes comando que llegan a este sistema vía puerto serie. Como era de
esperar, hay un procesador de mensajes. El procesador de mensajes conoce el
formato de los mensajes, es capaz de decodificarlos y, entonces, puede enviar el
mensaje al código que puede tratar la respuesta. Nada de esto es sorprendente,
excepto que el procesador de mensajes reside en el mismo fichero que el código
que interactúa con el hardware UART. EL procesador de mensajes estaba
contaminado con detalles de UART. El procesador de mensajes podría haber sido
software con una potencialmente larga vida útil pero en vez de eso es firmware.
Al procesador de mensajes se le denegó la oportunidad de convertirse en
software y esto no es lo correcto.
Yo he conocido y
entendido la necesidad de separar el software del hardware desde hace mucho
tiempo pero las palabras de Doug me aclararon cómo usar los términos “software”
y “firmware” en relación uno con el otro.
Para ingenieros y
programadores, el mensaje es claro; para de escribir tanto firmware y dar la
oportunidad al código de tener vida útil larga. Por supuesto, exigirlo no lo
hará. Veamos como se puede mantener limpia una arquitectura de software
incrustado para dar al software oportunidad de tener una vida larga y
útil.
Prueba APP-TITUDE
¿Por qué tanto potencial
software embebido se convierte en firmware? Esto parece que la mayoría del
énfasis es que el código embebido funcione y no tanto en cómo estructurarlo
para que tenga una vida útil. Kent Beck describe tres actividades en la
construcción software (el texto entre comillas son las palabras de Kent y entre
comillas las mías):
- “Primero
haz que funcione”. Estás fuera del negocio si no funciona.
- “Después
hazlo bien”. Refactorizar el código de manera que tú y otros puedan
entenderlo y evolucionarlo a medida que las necesidades cambian y
están mejor entendidas.
- “Entonces
haz esto rápido.” Refactorizar para las necesidades de rendimiento.
Muchos de los sistemas
software embebidos que veo parecen haber sido escritos con “Haz que funcione”
en mente, y quizá también por la obsesión por el “hazlo rápido” logrado por
añadir micro-optimizaciones en cada oportunidad. En el libro “The Mythical
Man-Month”, Fred Brooks nos sugiere “Cómo planear uno”. Kent y Fred están dando,
virtualmente, el mismo consejo: aprende cómo funciona, entonces haz una mejor
solución.
El software embebido no
es especial cuando se trata de estos problemas. La mayoría de las aplicaciones
no embebidas se construyen simplemente para trabajar, con poca consideración de
hacer un código correcto para una larga vida útil.
Hacer que una aplicación
funcione es lo que yo llamo la prueba “App-titude” para un programador. Los
programadores que sólo se preocupan por hacer que sus aplicaciones funcionen
están perjudicando a sus productos y empleadores. La programación es mucho más
que sólo hacer que una aplicación funcione.
Como un ejemplo de
código producido mientras se pasa la prueba “App-titude”, verifica estas
funciones localizadas en un archivo de un pequeño sistema embebido:
ISR(TIMER1_vect) { ...
}
ISR(INT2_vect) { ... }
void btn_Handler(void)
{ ... }
float calc_RPM(void) {
... }
static char
Read_RawData(void) { ... }
void Do_Average(void) {
... }
void
Get_Next_Measurement(void) { ... }
void
Zero_Sensor_1(void) { ... }
void
Zero_Sensor_2(void) { ... }
void Dev_Control(char
Activation) { ... }
char
Load_FLASH_Setup(void) { ... }
void
Save_FLASH_Setup(void) { ... }
void
Store_DataSet(void) { ... }
float bytes2float(char
bytes[4]) { ... }
void
Recall_DataSet(void) { ... }
void Sensor_init(void)
{ ... }
void uC_Sleep(void) {
... }
|
Esta lista de funciones
está en el orden que se encuentra en el archivo fuente. Ahora, voy a
separarlas agrupadas por conceptos.
Funciones que tienen
lógica de dominio.
float calc_RPM(void) {
... }
void Do_Average(void)
{ ... }
void
Get_Next_Measurement(void) { ... }
void
Zero_Sensor_1(void) { ... }
void
Zero_Sensor_2(void) { ... }
|
Funciones que tienen
configuración de la plataforma de software.
ISR(TIMER1_vect) { ...
}*
ISR(INT2_vect) { ... }
void uC_Sleep(void) {
... }
Functions that react
to the on off button press
void btn_Handler(void)
{ ... }
void Dev_Control(char
Activation) { ... }
A Function that can
get A/D input readings from the hardware
static char
Read_RawData(void) { ... }
|
Funciones que almacenan
valores para el almacenamiento persistente.
char
Load_FLASH_Setup(void) { ... }
void
Save_FLASH_Setup(void) { ... }
void
Store_DataSet(void) { ... }
float bytes2float(char
bytes[4]) { ... }
void
Recall_DataSet(void) { ... }
|
Funciones que no hacen
lo que su nombre implica.
void Sensor_init(void)
{ ... }
|
Mirando en otros
ficheros de esta aplicación encontré muchos impedimentos para entender el
código. También encontré una estructura de fichero que implicó que la única
manera de comprobar cualquier cosa de este código es en el objetivo embebido.
Virtualmente cada bit de este código sabe que está en una arquitectura especial
de microprocesador, usando construcciones de C extendidas “extended” que
vinculan el código a una cadena de herramientas y microprocesador en
particular. No hay manera para este código tener una vída larga útil a
menos que el producto nunca necesite moverse a un entorno de hardware
diferente.
Esta aplicación trabaja:
el ingeniero pasó los test de App-titude pero la aplicación no puede decir que
tenga una arquitectura limpia embebida.
El cuello de botella del
hardware
Hay muchos aspectos
especiales que los desarrolladores embebidos tienen que tratar que los
desarrolladores de no embebidos no. Por ejemplo, el espacio de memoria
limitada, las restricciones de tiempo o las líneas límite, la limitación IO,
interfaces de usuario no convencionales y sensores y conexiones al mundo real.
La mayoría del tiempo el hardware está desarrollado de forma concurrente
con el hardware y el firmware. Como un ingeniero desarrollando código para este
tipo de sistemas, tú puedes no tener un lugar donde ejecutar ese código. Si
esto no es suficientemente malo, una vez que obtienes el hardware, hay
probabilidades que ese hardware tenga sus propios defectos, haciendo el
progreso de desarrollo de software incluso más lento de lo habitual.
Sí, embebido es
especial. Los ingenieros embebidos son especiales pero el desarrollo de
embebido no es especial de manera que los principio de este libro se puedan
aplicar a los sistemas embebidos.
Uno de los problemas
especiales es el cuello de botella del hardware. Cuando el código embebido se
estructura sin aplicar los principios y prácticas de arquitectura limpia,
tendrás que afrontar el escenario en el cual tú puedes probar tu código sólo en
el objetivo. Si el objetivo es el único lugar donde son posibles las pruebas,
el cuello de botella hardware lo ralentizará.
No hay comentarios:
Publicar un comentario