Soluzione semplice vs complessa (ma efficiente in termini di prestazioni): quale scegliere e quando?


28

Ho programmato per un paio di anni e spesso mi sono trovato in un dilemma.

Esistono due soluzioni:

  • uno è semplice, cioè un approccio semplice, più facile da capire e mantenere. Implica ridondanza, lavoro extra (extra IO, elaborazione extra) e quindi non è la soluzione ottimale.
  • ma altri usano un approccio complesso, difficile da implementare, che spesso coinvolge l'interazione tra molti moduli ed è una soluzione efficiente in termini di prestazioni.

Quale soluzione dovrei cercare quando non ho un SLA con prestazioni elevate da soddisfare e anche la soluzione semplice può soddisfare lo SLA con prestazioni? Ho sentito disprezzo tra i miei colleghi sviluppatori per una soluzione semplice.

È buona norma trovare la soluzione complessa più ottimale se lo SLA delle prestazioni può essere soddisfatto con una soluzione semplice?


10
vedi: Come evitare "Intuizione di ottimizzazione errata dello sviluppatore"? "Sfortunatamente, gli sviluppatori hanno generalmente un'orribile intuizione su dove saranno effettivamente i problemi di prestazioni in un'applicazione ...."
moscerino

1
"Non il più ottimale" sarà ancora "abbastanza buono"? Quindi rimani con quello.

8
Sì. " Le mieux est l'ennemi du bien. " Voltaire. ("Perfetto è il nemico del bene.") Abbastanza buono è abbastanza buono - fino a quando il test delle prestazioni non dice diversamente.
David Hammen,

Trovo che (in generale) semplice implica efficiente. Quindi spesso non è necessario scendere a compromessi.
Dan,

2
"Sembra che la perfezione non sia raggiunta quando non c'è altro da aggiungere, ma quando non c'è più nulla da rimuovere." - Antoine de Saint-Exupery
keuleJ

Risposte:


58

Quale soluzione dovrei cercare quando non ho un SLA con prestazioni elevate da soddisfare e anche la soluzione semplice può soddisfare lo SLA con prestazioni?

Quello semplice. Soddisfa le specifiche, è più facile da capire, è più facile da mantenere ed è probabilmente molto meno buggy.

Quello che stai facendo per promuovere la soluzione efficiente in termini di prestazioni è introdurre nel tuo codice generalità speculativa e ottimizzazione prematura. Non farlo! Le prestazioni sono in contrasto con quasi ogni altra "ility" di ingegneria del software (affidabilità, manutenibilità, leggibilità, testabilità, comprensibilità, ...). Insegui le prestazioni durante i test indica che è davvero necessario inseguire le prestazioni.

Non inseguire le prestazioni quando le prestazioni non contano. Anche se è importante, è necessario inseguire le prestazioni solo nelle aree in cui il test indica l'esistenza di un collo di bottiglia delle prestazioni. Non lasciare che i problemi di prestazioni siano una scusa per sostituire simple_but_slow_method_to_do_X()con una versione più veloce se quella versione semplice non si presenta come un collo di bottiglia.

Le prestazioni avanzate sono quasi inevitabilmente gravate da una serie di problemi di odore di codice. Ne hai menzionati diversi nella domanda: un approccio complesso, difficile da attuare, un accoppiamento più elevato. Vale davvero la pena trascinarli dentro?


la tua risposta è molto utile
MoveFast

1
Il più semplice possibile, ma non più semplice; Il più veloce possibile, ma non più veloce; ecc.
user606723

2
"In caso di dubbio, usa la forza bruta";)
tdammers

I commenti nel codice possono essere sia catartici che utili qui. Un piccolo commento che evidenzia la soluzione complessa + veloce e perché non l'hai utilizzata, può farti sentire meno ignorato l'algoritmo ottimale. E può aiutare i manutentori a capire la tua scelta e indicarli nella giusta direzione se l'ottimizzazione è effettivamente necessaria in un secondo momento.
TheAtomicOption

12

Risposta breve: preferisci le soluzioni semplici a quelle complesse e ricorda i principi KISS e YAGNI

Poiché i requisiti e il software del progetto iniziale non sono mai perfetti, richiedono modifiche man mano che l'applicazione viene sviluppata / utilizzata. L'approccio iterativo nelle fasi di sviluppo è un ottimo abbinamento per iniziare cose semplici ed estenderle secondo necessità. Le soluzioni più semplici hanno spazio per la flessibilità e più facile da mantenere.

Inoltre, cercare di essere intelligenti e apportare alcune ottimizzazioni add-hoc durante la creazione dell'applicazione non è una buona pratica e può complicare eccessivamente la soluzione. Come è noto, "premature optimization is the root of all evil"- dal libro di Knuth


1
@ManojGumber, nessun problema ed è davvero l'essenza di ciò che a noi programmatori dovrebbe interessare al primo posto.
EL Yusubov,

8

Prendi una lezione da Knuth qui: "Dovremmo dimenticare piccole efficienze, diciamo circa il 97% delle volte: l'ottimizzazione prematura è la radice di tutti i mali".

Pensa alle tue soluzioni in questo ordine: in primo luogo, sempre, correttezza. In secondo luogo, migliorare la chiarezza e la semplicità. Terzo, e solo quando puoi dimostrare la necessità, l'efficienza.

L'aggiunta di efficienza ti costerà quasi sempre qualcosa di importante, e quindi dovrebbe essere perseguita solo quando sai che è necessario.


4
Nota che questo non significa che non dovresti scrivere una buona implementazione in primo luogo.

@ ThorbjørnRavnAndersen: ovviamente, ecco i primi due punti.
simon,

1
@simon la citazione è spesso usata come scusa per scegliere sciatta,

A proposito del tuo secondo punto: avevo un collega che spesso diceva che preferiva un codice errato ben strutturato e pulito prima degli spaghetti corretti.
Buhb,

@ ThorbjørnRavnAndersen le persone incompetenti useranno qualsiasi cosa per una scusa. Non ha alcun impatto sul valore del pensiero originale.
simon,

7

La semplicità è il presupposto dell'affidabilità . Se hai una soluzione semplice che funziona, provaci! È molto più facile ottimizzare un programma di lavoro che far funzionare un programma ottimizzato. Inoltre, non dimenticare la legge di Moore : se la tua soluzione semplice soddisfa gli obiettivi prestazionali oggi, probabilmente li schiaccerà 1 in un anno o due.


1 Non c'è alcuna garanzia lì, perché, come notato da Jimmy Hoffa nel suo commento qui sotto, la legge di Moore ha i suoi limiti.


Ti sei dimenticato dell'altra legge di Moore che afferma: "Oops, sulla mia prima legge ..." Mi dispiace capo, la legge di Moore non è più (gioco di parole). Non sono in disaccordo con il resto del tuo punto, vorrei solo un minimo avvertimento sull'ultima parte lì.
Jimmy Hoffa,

2
Siamo spiacenti, ma in tutta la mia esperienza in questo settore. i "set di lavoro" stanno aumentando molto più velocemente della velocità del nostro hardware, che viene costantemente aggiornato. Davvero, rimuoverei semplicemente il punto di legge di Moore.
user606723

@ user606723 La crescita del punto "set di lavoro" è ortogonale alla domanda "ottimizzata o semplice": il carico di lavoro li raggiungerà indipendentemente dalla soluzione che implementano. Il punto di introdurre la legge di Moore nel mix era di sottolineare che anche se la semplice soluzione è sottoposta a una certa pressione delle prestazioni al momento della stesura, la pressione diminuirà man mano che l'hardware diventa più veloce.
dasblinkenlight,

@dasblinkenlight, la crescita del workset non è più ortogonale alla domanda di quanto lo sia la legge di Moore. Il punto di portare il workset nel problema è che se una soluzione semplice è sottoposta a una certa pressione delle prestazioni al momento del rilascio, le prestazioni saranno insufficienti in un futuro molto vicino poiché il workset in aumento demolisce qualsiasi miglioramento delle prestazioni ottenuto da un hardware migliorato. Mentre sono tutto per software semplice, affidabile e mantenibile, rilasciare software che è già sotto pressione per le prestazioni al momento del rilascio e aspettarsi che la legge di Moore lo uniformi è una filosofia terribile.
user606723

3

È buona norma trovare la soluzione complessa più ottimale se lo SLA delle prestazioni può essere soddisfatto con una soluzione semplice?

Ottimale è una parola ambigua!

In definitiva, se ci sono molti rischi nel dover mantenere quello complesso, e se quello semplice è "abbastanza buono", sbaglierei sempre dal lato semplice.

Aggiungi il rischio che il complesso non sia abbastanza buono, quindi KISS è probabilmente la risposta giusta.


2

Preferirei quello semplice. Secondo me le ottimizzazioni premature causano tanti problemi quanti ne risolvono. In molti casi, un buon design consente di modificare determinate implementazioni in futuro, se diventano strozzature.

Quindi, alla fine, lo progetterò il più flessibile possibile, ma non sacrificherò troppo la semplicità per la flessibilità.


2

Quale costa di meno?

Il più delle volte, una soluzione semplice leggermente più lenta sarà perfettamente accettabile in termini di prestazioni e la semplicità rende più economico lo sviluppo, la manutenzione e alla fine la sostituzione.

D'altra parte, a volte la velocità è davvero importante e il guadagno finanziario che deriva anche da piccoli miglioramenti della velocità può essere di gran lunga superiore all'aumento dei costi di una soluzione più complicata. Ad esempio, radere 0,01 di tempo per completare una transazione può rendere un sistema di negoziazione di titoli molto più redditizio. Un miglioramento del 10% nell'efficienza di un sistema che supporta diversi milioni di utenti potrebbe comportare una riduzione significativa dei costi del server.

Quindi, la domanda che ti devi porre è: l' utilizzo della soluzione complessa ha un impatto sufficiente sulla linea di fondo per pagare il costo aggiuntivo? In realtà, dovresti probabilmente chiedere al tuo cliente di decidere poiché stanno pagando le bollette e stanno raccogliendo i potenziali benefici. Una buona opzione è quella di scegliere prima la soluzione semplice e offrire la soluzione più complessa come possibile miglioramento. Ciò ti consente di mettere in funzione il tuo sistema e dà al tuo client qualcosa per iniziare i test, e quell'esperienza può informare la decisione di implementare (o non implementare) la soluzione più complicata.


2

Quando si valutano due approcci, uno è più semplice ma meno efficiente mentre l'altro è più complesso e più efficiente, si deve considerare il problema e il dominio del progetto.

Prendi in considerazione un progetto multi-miliardario per l'industria sanitaria che ha pianificato la vita per oltre 15 anni di manutenzione e +20 anni di utilizzo. In tale progetto le prestazioni sicuramente non saranno una preoccupazione, ma la complessità e la struttura del progetto possono causare gravi problemi per la manutenzione del progetto, che dura almeno per quei 15 anni. La manutenibilità e la semplicità vengono prima di tutto.

Quindi, considera un altro esempio. Un motore di gioco per console che dovrebbe alimentare i prossimi giochi dell'azienda per i prossimi 5+ anni. Poiché i giochi sono programmi estremamente limitati dalle risorse, in molti casi l'efficienza va prima della manutenibilità. Scrivere strutture di dati e algoritmi molto specifici per alcuni compiti può essere molto importante anche se va contro qualsiasi tipo di "best practice" di sviluppo software. Un buon esempio di ciò potrebbe essere la progettazione orientata ai dati in cui vengono archiviati i dati in matrici di dati simili, anziché in oggetti reali. Questo per aumentare il riferimento della località e come tale aumentare l'efficienza della cache della CPU. Non pratico, ma molto cruciale nel dominio dato.


1

Questa è sempre una domanda difficile e vedo le risposte oscillare in un modo, quindi giocherò dall'altra parte, anche se non pretendo che nessuna risposta sia corretta, è un argomento molto morbido e caso per caso.

Una cosa su una soluzione complessa ma ad alte prestazioni è che puoi sempre documentare il diavolo sempre vivo da essa. In genere sono un fan del codice auto-documentante, ma sono anche un fan del software che risponde in un periodo di tempo che mi fa sentire come se non mi rallentasse. Se vai con la soluzione complessa ma ad alte prestazioni, considera cosa puoi fare per renderlo non così male:

Avvolgilo in un'interfaccia, mettilo in un assieme da solo, forse anche un processo tutto suo. Renderlo accoppiato il più liberamente possibile con una parete di astrazione il più spessa possibile per evitare perdite . Scrivi molti test unitari per salvare le regressioni in futuro.

Documentalo nel codice, considera anche la possibilità di scrivere della vera documentazione. Pensa a strutture di dati complesse e al modo in cui sono documentate, immagina di provare a capire l'implementazione di una di esse dal codice senza un libro / articolo di Wikipedia sulle strutture di dati per spiegarlo. Eppure tutti accettiamo che queste complesse strutture di dati siano in realtà buone cose ed è utile che qualcuno le abbia implementate nelle nostre lingue.

Ricorda che stiamo tutti inviando messaggi su uno stack TCP / IP che è probabilmente tanto difficile quanto il codice può ottenere se qualcuno di noi lo guardasse, espressamente in modo che funzioni come tutti noi lo richiediamo. Forse il tuo problema non richiede questo livello di ottimizzazione, forse lo fa, ma fai attenzione quando affronti questa domanda come tutti noi dobbiamo di volta in volta: ci sono draghi lì.


0

Sto arrivando a questo lavoro in aree in cui non vi è alcun SLA sulle prestazioni. Quando si tratta di renderer offline nella computer grafica, non ci sono "prestazioni soddisfacenti" per gli utenti, perché stanno già distribuendo enormi somme di denaro per distribuire il calcolo su cloud e rendere le farm anche con i renderer all'avanguardia per produrre immagini e cornici di qualità produttiva per i film, ad es

Devo tuttavia affermare come uno che lavora in questo settore da molti anni che qualsiasi soluzione che degrada in modo significativo la manutenibilità a favore dell'efficienza sta effettivamente lavorando contro i requisiti di prestazioni in continua evoluzione. Perché se non riesci a mantenere efficacemente la tua soluzione per gli anni a venire mentre le cose si stanno spostando sotto i tuoi piedi (sia in termini di codice circostante sia in ciò che gli utenti si aspettano che i concorrenti continuino a sovraperformarsi a vicenda), allora la tua soluzione sta già lavorando verso l'obsolescenza e in necessità di sostituzione all'ingrosso.

Non vedo lo scopo ultimo di profilatori come VTune come un modo per rendere il mio codice più veloce. Il loro ultimo valore è assicurarsi che non sto degradando la mia produttività per soddisfare le sempre crescenti richieste di prestazioni. Se devo assolutamente applicare un po 'di micro-ottimizzazione dall'aspetto grossolano, allora il profiler, combinato con l'esecuzione su casi di utenti reali (e non su alcuni casi di test che immagino potrebbero essere importanti), si assicura di applicare tale inevitabilmente aspetto grossolano ottimizzazioni molto, molto giudiziose solo per i migliori hotspot che compaiono, oltre a documentarle con molta attenzione perché dovrò inevitabilmente rivisitarle, mantenerle, modificarle e modificarle per gli anni a venire se tale soluzione rimane praticabile.

E soprattutto se la tua soluzione ottimizzata prevede un maggiore accoppiamento, sarei davvero riluttante a usarla. Tra le metriche più preziose che ho imparato ad apprezzare nelle aree più critiche per le prestazioni del codebase c'è il disaccoppiamento (come nel minimizzare la quantità di informazioni che qualcosa deve funzionare, il che minimizza anche la probabilità che richieda cambiamenti a meno che non abbia bisogno di cambiamenti diretti ), poiché queste aree critiche moltiplicano significativamente le ragioni per cui le cose cambiano. Ciò significa che meno informazioni richiede qualcosa per funzionare, meno ragioni ha per il cambiamento e minimizzare le ragioni del cambiamento è davvero una parte enorme del miglioramento della produttività nelle mie particolari aree di interesse perché le cose dovranno cambiare costantemente comunque (noi diventerò obsoleto tra un anno altrimenti),

Per me le soluzioni più grandi ed efficaci che ho trovato sono quelle in cui efficienza, manutenibilità e produttività non sono diametralmente opposte. La ricerca per me è quella di provare a rendere questi concetti più armoniosi che si possano realizzare.

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.