Pericoli di enorme applicazione monolitica


20

Il grande progetto a cui sto lavorando da un paio d'anni è un'applicazione di controllo (e tutto) di un dispositivo avanzato, cuore del suo firmware.

Il dispositivo è piuttosto avanzato, con funzionalità più diverse di quanto potrei dire dalla memoria, e il 98% di esse è gestito da questo enorme eseguibile. In una mano, il programma è abbastanza mantenibile, ben modulare all'interno, adeguatamente documentato, c'è una ragionevole separazione delle funzionalità da directory e file e così via.

Ma alla fine viene tutto raggruppato in un'unica applicazione che fa di tutto, dalla comunicazione remota al database, alla gestione del touchscreen, alla gestione di una dozzina di vari protocolli di comunicazione, misurazioni, diversi algoritmi di controllo, acquisizione video, ora dell'alba e data di pasqua (sul serio, e sono necessario per scopi molto seri!) ... In generale, roba che è molto sottilmente correlata, spesso collegata solo attraverso alcuni dati che trapelano tra alcuni moduli distanti.

Potrebbe essere fatto come diversi eseguibili separati che comunicano tra loro, ad esempio su socket, con scopi più specifici, magari caricati / scaricati secondo necessità, e così via. Nessun motivo specifico per cui è stato realizzato in questo modo.

In una mano, funziona e funziona bene. Il progetto è più semplice, senza mantenere la compilazione di più binari. Anche la struttura interna è più semplice, quando puoi semplicemente chiamare un metodo o leggere una variabile invece di parlare tramite socket o memoria condivisa.

Ma d'altra parte, la dimensione, la scala di questa cosa mi fa semplicemente paura, mi sembra di pilotare Titanic. Mi è stato sempre insegnato a modularizzare e raggruppare tutto in un file gigantesco mi sembra sbagliato. Un problema che conosco è un grave arresto anomalo di un modulo (anche insignificante) che si arresta in modo anomalo, ma la qualità del codice assicura che ciò non accada realmente nelle versioni di rilascio. Altrimenti, la separazione interna e la programmazione difensiva assicurano che ciò funzionerà per lo più correttamente anche se la metà dei moduli interni non funziona normalmente per qualche motivo.

Quali altri pericoli ho trascurato? Perché questo mi fa paura? È solo una paura irrazionale dell'ignoto? Realizzare progetti così importanti in questo modo è una pratica accettata? Calma le mie paure o dammi una buona ragione per rifattare la versione 2.0 in più binari più piccoli.


7
Se il sole sorge troppo presto, l' Inghilterra si sposterà verso il mare.
Max

1
Oppure la pressione nel nucleo della Terra aumenta leggermente.
StuperUser

1
@Maxpm Vedo quello che hai fatto lì ... xkcd.com/687
teto

3
@Maxpm: Fortunatamente, la nostra app non genera albe e tramonti. Confidiamo che la principessa Celestia non fallirà nel suo lavoro.
SF.

1
@rwong: 1. Il dispositivo viene arrestato per gli aggiornamenti. Sebbene sopravviverebbe agli aggiornamenti al volo, non vogliamo risultati imprevisti nel caso in cui l'aggiornamento vada storto per qualsiasi motivo. 2. ARM9 single-core con Linux incorporato. C'è un secondo, che controlla la CPU in esecuzione senza sistema operativo, verificando che la CPU principale produca un output sano.
SF.

Risposte:


5

A parte il piccolo commento alla fine (secondo, supervisione della CPU) potresti descrivere la mia azienda. Sì, anche noi abbiamo bisogno della Pasqua.

Bene, siamo un po 'più avanti. Abbiamo diviso il grande eseguibile e provato a usare componenti standard per bit standard. Non è esattamente il grande miglioramento che speri. In effetti, le prestazioni stanno diventando un grosso problema anche per l'hardware più robusto. E i costi di manutenzione non sono davvero diminuiti ora che ci sono tonnellate di codice per serializzare e sincronizzare i dati su interfacce strette.

La lezione che ho imparato? Avere un singolo eseguibile è una soluzione collaudata per piccoli sistemi e abbiamo decenni di esperienza nella gestione. Tutti i nostri strumenti lo supportano in modo nativo. La modularità può essere eseguita anche all'interno di un singolo eseguibile e quando è necessario scendere a compromessi sulla modularità per altri motivi, l'hack rimane piccolo.


Grazie - nessuna voce "best practice da seguire / sacrificare" e "ponderazione di potenziali benefici rispetto a potenziali svantaggi" sono sempre utili quanto qualcuno con esperienza diretta dall'altra parte della barriera.
SF.

23

Il dispositivo è piuttosto avanzato, con funzionalità più diverse di quanto potrei dire dalla memoria, e il 98% di esse è gestito da questo enorme eseguibile. In una mano, il programma è abbastanza mantenibile, ben modulare all'interno, adeguatamente documentato, c'è una ragionevole separazione delle funzionalità da directory e file e così via.

L'hai detto tu stesso - è abbastanza mantenibile, ben modulare ...

A mio avviso, e la maggior parte dei dirigenti sarà d'accordo con me su questo, i cambiamenti non dovrebbero mai essere fatti per motivi di cambiamenti. Non c'è nulla di sbagliato in questo programma (la tua descrizione) a parte il fatto che non segue le ultime tendenze di programmazione (che sono menzionate in altre risposte).

Sì, è un programma più grande ... molti prima lo sono stati anche. È anche ben documentato, quindi tutto ciò che devi fare è studiare la sua organizzazione interna e vedrai la logica in essa. Dubito che tutti quelli davanti a te che l'hanno scritto fossero incompetenti. Quindi, esploralo un po ', imparalo ... dopo quello, mantienilo così com'è fino a quando non si apre una solida ragione per riscriverlo. Il tuo manager ti sarà grato per avere un buon rapporto costi / effetti.

Quali altri pericoli ho trascurato? Perché questo mi fa paura? È solo una paura irrazionale dell'ignoto? Realizzare progetti così importanti in questo modo è una pratica accettata? Calma le mie paure o dammi una buona ragione per rifattare la versione 2.0 in più binari più piccoli.

Ti fa paura perché è grande - ma poi, nessuno si aspetta che tu impari tutto a memoria in una settimana. Quindi lavora, pezzo per pezzo, a poco a poco, fino a quando non ne avrai la certezza. Alla fine, imparerai che è probabilmente ben organizzato così com'è e come è organizzato.

Se lo riscrivessi, realizzeresti lo stesso, ma allo stesso tempo lo rovinerei per tutti coloro che erano abituati alla precedente organizzazione del codice. In questo modo, solo tu devi "adattarti".


16

Mi sentirei meglio se dicessi di aver avvolto tutto nei test unitari. In caso contrario, è necessario creare una suite di test prima ancora di pensare a rearchitecting l'applicazione.

Avere una suite di test migliorerà la tua comprensione dell'applicazione e ti dirà quando un cambiamento nell'applicazione rompe qualcosa.


2
Ma questo vale per entrambe le possibili architetture ...
SF.

3
Sì, lo fa ...
Robert Harvey,

10
... e quindi questa risposta non aggiunge nulla alla discussione se non per promuovere i test unitari.
benzado,

2
@benzado: che, nello scenario del PO, è praticamente di fondamentale importanza.
Robert Harvey,

2
@ironcode: dai un'occhiata a un libro del tipo "Lavorare efficacemente con il codice legacy". La prima cosa che dice in quel libro è "Se non hai già una serie di test unitari con una copertura di codice elevato, scrivili prima, prima di fare qualsiasi altra cosa " . Direi che qui i consigli sono più che pertinenti, dato che il PO ha specificamente chiesto "Quali altri pericoli ho trascurato".
Robert Harvey,

8

Se il codice è ben modularizzato con basso accoppiamento e elevata coesione, viene effettivamente suddiviso. Le spese generali di comunicazione dovrebbero essere inferiori all'interno di un processo rispetto a quanto accadrebbe con processi multipli.

Per i sistemi embedded, il tuo unico processo potrebbe eliminare la necessità di implementare un O / S per eseguire tutti i processi che stai creando. Dovresti anche implementare un sistema per verificare che tutti i processi siano in esecuzione e riavviarli se possibile. Se non fosse possibile, dovresti reagire di conseguenza.

Dividere il codice in file eseguibili separati aumenterebbe anche la dimensione complessiva del codice sorgente in quanto sarebbe necessario implementare tutto il codice client / server tra i moduli. Avresti anche bisogno di più casi di test per gestire questo codice e casi in cui il processo del server non era presente. I grandi progetti sono grandi, eliminando le complessità non necessarie come sembra essere stato fatto qui aiuta a mantenerle le più piccole possibile.

Il test è una specie di aringa rossa qui, poiché i problemi saranno ancora lì con o senza test. Dovrebbero sicuramente essere incoraggiati buoni test con entrambe le scelte progettuali. Mi aspetto che il test sia più semplice con il codice monolitico.

Forzare un arresto quando necessario è anche più facile con un eseguibile monolitico.


1
+1, l'ingegneria riguarda i compromessi, anche i binari più piccoli hanno un costo
benzado,

+1 Sono d'accordo con tutto il cuore. Non è stato fornito alcun motivo specifico per giustificare più eseguibili. La comunicazione e il coordinamento tra eseguibili ha il suo prezzo.
Erick Robertson,

+1: se non è rotto, non aggiustarlo.
Bob Murphy,

1

Se dovessi lavorare su un'applicazione monolitica così grande, le cose che mi farebbero impazzire sono la mancanza di incapsulamento, bassa coesione, alto accoppiamento e come testare tutto questo. I grandi monoliti sono spesso un invito ad abbandonare la corretta architettura e iniziare la discesa in una grande palla di fango .

Una volta che ciò accade, i test diventano un incubo e sei sulla buona strada per l'obsolescenza.

Tuttavia, se il tuo codice è ben strutturato e ben mantenuto e vengono rispettati i principi di alta coesione, basso accoppiamento e incapsulamento corretto, vedo poche ragioni per rifattarlo in unità più piccole.

Tuttavia, vuoi fare buoni test.


1

Idealmente, la risposta è sì. Avere più binari ha il potenziale per renderlo più stabile ....

... tuttavia, hai anche detto che il codice all'interno della base di codice monolitico è ben scritto e modulare, il che significa che non hai a che fare con un enorme pasticcio aggrovigliato, solo una grande base di codice ...

Nel complesso, direi che il detto applicabile è "Non lasciare che il perfetto sia nemico del bene". Sebbene ritenga che tu abbia ragione nel dire che una base di codice monolitico è cattiva, sento anche che non vale la pena preoccuparsene.

Sarebbe ragionevole andare avanti inserendo nuovi pezzi di codice nei propri file binari, ma tornare indietro e refactoring probabilmente non vale la pena.


1

Se stai usando un singolo processo, c'è qualche possibilità che un puntatore selvaggio da uno dei tuoi sottomoduli possa corrompere un pezzo critico di memoria (e mandare in crash l'intera cosa).

Se si utilizzano processi diversi, almeno non si utilizza lo stesso heap o stack di chiamate e potrebbe anche essere più semplice riavviare un singolo sottoprocesso.

Anche la struttura interna è più semplice, quando puoi semplicemente chiamare un metodo o leggere una variabile invece di parlare tramite socket o memoria condivisa.

La suddivisione di tutto in più processi ti costringerà anche a ripulire il progetto ed evitare che ogni modulo inizi a utilizzare metodi interni di altri moduli.

Detto questo, è probabilmente un compito scoraggiante.

Quello che potresti iniziare a fare è decidere che ogni nuovo modulo dovrebbe essere un processo isolato.


Stai assumendo moltissimo sull'hardware di runtime e l'ambiente del sistema operativo, specialmente quando sono coinvolti firware e dispositivi integrati.
Patrick Hughes,

0

Quando entro nel regno in cui il progetto è troppo grande per ingigantire tutto in una volta, creo un diagramma da appendere al muro che delinea tutte le grandi sezioni e il modo in cui si incastrano. Quindi, quando lavoro, posso fare riferimento al modulo su cui mi sto concentrando e avere un promemoria visivo di come si adatta al tutto.

È del tutto possibile che le complessità e i pericoli legati al mantenimento di un sistema di build e versioning per più binari disconnessi supereranno di gran lunga il disagio con un progetto così ampio e monolitico.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.