Preambolo:
Nei commenti sono state sollevate alcune obiezioni, e penso che derivino in gran parte da un fraintendimento di ciò che intendiamo quando diciamo "ottimizzazione prematura" - quindi volevo aggiungere un piccolo chiarimento al riguardo.
"Non ottimizzare prematuramente" non significa "scrivere codice che sai essere dannoso, perché Knuth dice che non ti è permesso ripulirlo fino alla fine"
Significa "non sacrificare tempo e leggibilità per l'ottimizzazione fino a quando non sai quali parti del tuo programma hanno effettivamente bisogno di aiuto per essere più veloci". Poiché un programma tipico trascorre la maggior parte del tempo in alcuni colli di bottiglia, investire nell'ottimizzazione di "tutto" potrebbe non ottenere lo stesso incremento di velocità del focalizzare lo stesso investimento solo sul codice del collo di bottiglia.
Ciò significa che, in caso di dubbio , dovremmo:
Preferisci un codice semplice da scrivere, chiaro da capire e facile da modificare per i principianti
Verifica se è necessaria un'ulteriore ottimizzazione (di solito eseguendo la profilazione del programma in esecuzione, anche se un commento sotto le note fa le analisi matematiche - l'unico rischio è che devi anche verificare che la tua matematica sia giusta)
Un'ottimizzazione prematura non è :
Decisioni architettoniche per strutturare il codice in modo tale da adattarsi alle proprie esigenze, scegliendo moduli / responsabilità / interfacce / sistemi di comunicazione appropriati in modo ponderato.
Semplici efficienze che non richiedono più tempo o rendono più difficile la lettura del codice. Cose come l'uso della digitazione forte possono essere sia efficienti che chiari le tue intenzioni. La memorizzazione nella cache di un riferimento invece di cercarlo ripetutamente è un altro esempio (a patto che il tuo caso non richieda una complessa logica di invalidazione della cache - forse tieni duro a scriverlo fino a quando non avrai profilato nel modo semplice prima).
Utilizzando l'algoritmo giusto per il lavoro. A * è più ottimale e più complesso della ricerca esaustiva di un grafico di pathfinding. È anche uno standard del settore. Ripetere il tema, attenersi a metodi collaudati come questo può effettivamente rendere il codice più facile da capire rispetto a se si fa qualcosa di semplice ma in contrasto con le migliori pratiche conosciute. Se hai esperienza con i colli di bottiglia nell'implementazione della funzione di gioco X in un modo su un progetto precedente, non è necessario ripetere nuovamente lo stesso collo di bottiglia su questo progetto per sapere che è reale: puoi e dovresti riutilizzare le soluzioni che hanno funzionato in passato Giochi.
Tutti questi tipi di ottimizzazioni sono ben giustificati e generalmente non sarebbero etichettati "prematuri" (a meno che non si stia scendendo in una tana di coniglio implementando un tracciato all'avanguardia per la mappa della scacchiera 8x8 ...)
Quindi ora con quello chiarito, sul perché potremmo trovare questa politica utile nei giochi in particolare:
Soprattutto in gamedev, la velocità di iterazione è la cosa più preziosa. Spesso implementeremo e reimplementeremo molte più idee di quelle che alla fine verranno fornite con il gioco finito, cercando di "trovare il divertimento".
Se riesci a prototipare un meccanico in un modo semplice e forse un po 'ingenuo e testarlo il giorno successivo, sei in una posizione molto migliore rispetto a se trascorri una settimana a crearne prima la versione più ottimale. Soprattutto se si scopre che fai schifo e finisci per lanciare quella funzione. Farlo in modo semplice in modo da poter eseguire i test in anticipo può risparmiare un sacco di lavoro sprecato ottimizzando il codice che non conservi.
Il codice non ottimizzato è anche generalmente più facile da modificare e provare diverse varianti rispetto al codice che è finemente ottimizzato per fare una cosa precisa in modo ottimale, che tende a essere fragile e più difficile da modificare senza romperlo, introdurre bug o rallentarlo. Pertanto, mantenere il codice semplice e facile da modificare spesso vale una piccola inefficienza di runtime durante gran parte dello sviluppo (di solito stiamo sviluppando su macchine al di sopra delle specifiche di destinazione, in modo da poter assorbire l'overhead e concentrarci sull'esperienza di destinazione prima) fino a quando abbiamo bloccato ciò di cui abbiamo bisogno dalla funzione e possiamo ottimizzare le parti che ora sappiamo essere lente.
Sì, il refactoring di parti del progetto in fase avanzata di sviluppo per ottimizzare i punti lenti può essere difficile. Ma lo è anche il refactoring ripetutamente durante lo sviluppo perché le ottimizzazioni apportate il mese scorso non sono compatibili con la direzione in cui il gioco si è evoluto da allora, o stavano risolvendo qualcosa che si è rivelato non essere il vero collo di bottiglia una volta ottenute più funzionalità e contenuti nel.
I giochi sono strani e sperimentali: è difficile prevedere come si evolverà un progetto di gioco e le sue esigenze tecnologiche e dove le prestazioni saranno ridotte. In pratica, finiamo spesso per preoccuparci delle cose sbagliate: cerca tra le domande sulla performance qui e vedrai emergere un tema comune di sviluppatori che vengono distratti da cose su carta che probabilmente non è affatto un problema.
Per fare un esempio drammatico: se il tuo gioco è associato alla GPU (non insolito), tutto quel tempo speso per l'ottimizzazione e il threading del lavoro della CPU potrebbe non produrre alcun beneficio tangibile. Invece, tutte quelle ore di sviluppo avrebbero potuto essere impiegate per implementare e perfezionare le funzionalità di gioco, per una migliore esperienza del giocatore.
Nel complesso, la maggior parte del tempo che passi a lavorare su un gioco non sarà speso per il codice che finisce per essere il collo di bottiglia. Soprattutto quando si lavora su un motore esistente, le cose super costose del circuito interno nei sistemi di rendering e fisica sono in gran parte fuori dalle tue mani. A quel punto, il tuo compito negli script di gioco è sostanzialmente quello di stare alla larga dal motore - fintanto che non ci metti una chiave lì, probabilmente uscirai abbastanza bene per una prima build.
Quindi, a parte un po 'di igiene del codice e budget (ad es. Non cercare / costruire ripetutamente roba se puoi riutilizzarla facilmente, mantieni modeste le tue ricerche di pathfinding / fisica o i readback della GPU, ecc.), Prendendo l'abitudine di non esagerare -ottimizzare prima di sapere dove sono i veri problemi si rivela positivo per la produttività - salvarci dal perdere tempo a ottimizzare le cose sbagliate e mantenere il nostro codice più semplice e facile da modificare nel complesso.