Pourquoi est-il si mauvais d'optimiser trop tôt?

168

Après avoir examiné un peu l'optimisation, j'ai découvert (littéralement partout) qu'il semble un péché universellement reconnu d'optimiser un jeu trop tôt.

Je ne comprends vraiment pas cela. Ne serait-il pas incroyablement difficile de modifier certaines des structures de base du jeu à la fin, plutôt que de les développer la première fois en tenant compte de la performance?

Je pense que attendre que le jeu soit terminé vous dira si vous avez besoin d'optimisations, mais si vous le faites quand même, après tout, cela pourrait élargir la variété des périphériques sur lesquels le jeu pourrait tourner, ce qui augmenterait le nombre de potentiels. joueurs.

Quelqu'un pourrait-il m'expliquer pourquoi l'optimisation trop tôt est une si mauvaise idée?

mr-matt
la source
Les commentaires ne sont pas pour une discussion prolongée; cette conversation a été déplacée pour discuter .
Josh
3
Il ne pourrait pas être plus facile de répondre à cela: "ça fait perdre du temps". Vous pourriez aussi bien demander "pourquoi essayer d'économiser de l'argent lors de l'achat?"
Fattie
27
Inversement, notez que de nombreux ingénieurs disent tout simplement que la phrase "ne pas optimiser trop tôt" est tout simplement fausse . La phrase devrait être simplement: "n'optimisez pas avant de savoir quoi optimiser". Donc, tout simplement, s’il existe trois systèmes A, B et C, il est totalement inutile d’optimiser A si, finalement, A n’est en aucun cas un goulet d’étranglement, et C est en fait le goulot d’étranglement. Dans cet exemple, évidemment, optimiser A aurait été une perte de temps totale. Donc, tout simplement, n'optimisez pas avant de savoir lequel de A, BC doit optimiser: c'est tout ce que cela signifie, c'est aussi simple que cela.
Fattie
2
Optimiser la classe temporelle de votre application au cours du développement est très différent d’essayer de supprimer quelques instructions d’une boucle qui est généralement du temps constant. Concentrez-vous sur O (n) contre O (n log n) au lieu de "écrire une boucle for de cette façon enregistre une instruction de la CPU".
1
@phyrfox En fait, réduire le temps de chargement me semble plus impressionnant. Un temps de chargement de trois secondes est perceptible. Je ne suis pas sûr si 55fps à 60fps est perceptible.
Immibis

Réponses:

237

Préambule:

Quelques objections ont été soulevées dans les commentaires et je pense qu'elles découlent en grande partie d'une incompréhension de ce que nous entendons par «optimisation prématurée» - je voulais donc ajouter un peu de clarification à ce sujet.

"Ne pas optimiser prématurément" ne signifie pas "écrire du code que vous savez mauvais, parce que Knuth dit que vous n'êtes pas autorisé à le nettoyer jusqu'à la fin"

Cela signifie "ne sacrifiez pas le temps et la lisibilité pour l'optimisation avant de savoir quelles parties de votre programme ont réellement besoin d'aide pour être plus rapide". Dans la mesure où un programme typique passe le plus clair de son temps dans quelques goulots d'étranglement, investir dans l'optimisation de "tout" ne vous donnera peut-être pas le même gain de vitesse que de concentrer cet investissement sur le code goulot.

Cela signifie qu'en cas de doute , nous devrions:

  • Préférez un code simple à écrire, clair à comprendre et facile à modifier pour les débutants

  • Vérifiez si une optimisation supplémentaire est nécessaire (généralement en profilant le programme en cours, bien qu'un commentaire ci-dessous indique d'effectuer une analyse mathématique - le seul risque que vous rencontrez est également de vérifier que vos calculs sont corrects)

Une optimisation prématurée n'est pas :

  • Décisions architecturales pour structurer votre code de manière à l'adapter à vos besoins - en choisissant les modules / responsabilités / interfaces / systèmes de communication appropriés de manière réfléchie.

  • Des performances simples qui ne prennent pas trop de temps et ne rendent pas votre code plus difficile à lire. L'utilisation de dactylographes forts peut être efficace et clarifier votre intention. La mise en cache d'une référence au lieu de la rechercher de manière répétée est un autre exemple (tant que votre cas ne nécessite pas une logique complexe d'invalidation de cache - conservez peut-être l'écriture jusqu'à ce que vous ayez d'abord profilé de manière simple).

  • Utiliser le bon algorithme pour le travail. A * est plus optimal et plus complexe que la recherche exhaustive d’un graphe de trajectoire. C'est aussi un standard de l'industrie. Répéter le thème en restant fidèle à des méthodes éprouvées comme celle-ci peut en réalité rendre votre code plus facile à comprendre que si vous faites quelque chose de simple mais qui va à l’encontre des meilleures pratiques connues. Si vous avez déjà rencontré des goulets d'étranglement lors de l'implémentation de la fonctionnalité de jeu X dans un projet précédent, vous n'avez pas besoin de répéter le même goulot d'étranglement pour savoir qu'il est réel. Vous pouvez et devez réutiliser des solutions qui fonctionnaient depuis longtemps. Jeux.

Tous ces types d'optimisations sont bien justifiés et ne seront généralement pas qualifiés de "prématurés" (à moins que vous ne perdiez de vue un lapin mettant en œuvre une orientation de pointe pour votre carte d'échiquier 8x8 ...)

C’est pourquoi , maintenant que tout est clair, pourquoi nous pourrions trouver cette politique utile dans les jeux en particulier:


Dans gamedev en particulier, la vitesse d'itération est la chose la plus précieuse. Nous allons souvent implémenter et ré-implémenter beaucoup plus d'idées que ce qui sera livré avec le jeu fini, en essayant de "trouver le plaisir".

Si vous pouvez prototyper un mécanicien de manière simple et peut-être un peu naïve et le tester le lendemain, vous êtes dans une bien meilleure position que si vous passiez d'abord une semaine à en faire la version la plus optimale. Surtout s'il s'avère que c'est nul et que vous finissez par jeter cette fonctionnalité. Le faire de manière simple afin de pouvoir effectuer des tests plus tôt permet d’économiser une tonne de travail inutile en optimisant du code que vous ne gardez pas.

Le code non optimisé est également généralement plus facile à modifier et à essayer différentes variantes que le code conçu avec précision pour effectuer une tâche précise de manière optimale, qui a tendance à être fragile et plus difficile à modifier sans le casser, en introduisant des bugs ou en le ralentissant. Donc, garder le code simple et facile à modifier vaut souvent un peu d'inefficacité d'exécution pendant la majeure partie du développement (nous développons généralement sur des machines supérieures à la spécification cible, afin que nous puissions absorber les frais généraux et nous concentrer sur l'obtention de l'expérience cible en premier) jusqu'à ce que nous 'a verrouillé ce dont nous avons besoin de la fonctionnalité et peut optimiser les pièces que nous savons maintenant lentes.

Oui, il peut être difficile de restructurer certaines parties du projet à la fin du développement afin d'optimiser les points lents. Mais il en va de même pour le refactoring à plusieurs reprises tout au long du développement, car les optimisations que vous avez effectuées le mois dernier ne sont pas compatibles avec l'évolution du jeu depuis, ou corrigeaient quelque chose qui n'était pas le véritable goulot d'étranglement une fois que vous disposiez de plus de fonctionnalités et de contenu dans.

Les jeux sont étranges et expérimentaux - il est difficile de prédire comment un projet de jeu et ses besoins technologiques vont évoluer et où la performance sera la plus serrée. En pratique, nous finissons souvent par nous inquiéter des mauvaises choses - parcourez les questions de performances et vous verrez apparaître un thème commun: les développeurs se laisser distraire par des choses sur papier qui ne sont probablement pas un problème du tout.

Pour prendre un exemple dramatique: si votre jeu est lié au GPU (pas rare), alors tout ce temps passé à hyper-optimiser et à fileter le travail de la CPU pourrait ne produire aucun avantage tangible. Toutes ces heures de développement auraient pu être consacrées à la mise en œuvre et au perfectionnement des fonctionnalités de jeu, pour une meilleure expérience du joueur.

Globalement, la plupart du temps que vous passez à travailler sur un jeu ne sera pas consacré au code qui finit par être le goulot d'étranglement. Surtout lorsque vous travaillez sur un moteur existant, la boucle extrêmement coûteuse des systèmes de rendu et de physique est en grande partie hors de votre portée. À ce stade, votre travail dans les scripts de jeu consiste à rester fondamentalement à l'écart du moteur - tant que vous ne lancez pas une clé, vous obtiendrez probablement un résultat assez bon pour une première construction.

Donc, mis à part un peu d’hygiène de code et de budgétisation (par exemple, ne cherchez pas et ne construisez pas à répétition des choses si vous pouvez facilement les réutiliser, gardez vos requêtes de recherche de trajectoire / physique ou les relectures de GPU modestes, etc.), en prenant l’habitude de ne pas oublier -optimiser avant de savoir où sont les vrais problèmes s'avère bon pour la productivité - nous évite de perdre du temps à optimiser les mauvaises choses et rend notre code plus simple et plus facile à peaufiner.

DMGregory
la source
38
Nous discutons plus en détail de StackOverflow ici , en insistant sur l’importance de la lisibilité et de la clarté du code et sur le danger de rendre le code plus difficile à comprendre (et plus facile à introduire dans les bogues) en l’optimisant prématurément.
DMGregory
8
Très bonne réponse, j'aimerais ajouter, en réponse à " ne serait-il pas incroyablement difficile de modifier certaines des structures de base du jeu à la fin, plutôt que de les développer la première fois en tenant compte de la performance? ", Directement, que Bien sûr, vous essayez de concevoir pour l'efficacité en premier lieu. Quand on vous présente deux choix, vous choisissez le plus efficace. A défaut, vous écrivez le jeu de manière aussi modulaire que possible avec des interfaces bien définies. Vous pouvez ensuite modifier les mécanismes dans chaque module sans restructurer la base de code entière.
Baldrickk
1
@Baldrickk Je dirais que cela vaut la peine d'être partagé comme réponse supplémentaire. (Je l'aurais voté!) Ma réponse omet l'importance de l'architecture et de la planification pour éviter de créer de gros problèmes en premier lieu. Quant à la référence de Gizmo au "développement de programmes en général", c'est de là que vient ce concept d'optimisation prématurée. Comme indiqué ci-dessus, une mauvaise optimisation peut devenir une dette technique aussi facilement qu'une optimisation manquante. Mais nous devrions souligner que nous ne faisons jamais les choses de manière délibérément lente, préférant simplement la simplicité et la lisibilité jusqu'à ce que nous puissions profiler et trouver les véritables problèmes
DMGregory
1
Bien que je sois probablement le plus inexpérimenté parmi vous, je dois dire que je trouve cette "racine d'optimisation prématurée de tout le mal" un peu étrange. Il y a deux ans environ, j'essayais de faire quelque chose dans Unity3D. J'ai écrit quelques requêtes LINQ, chacune utilisant la précédente. J'ai regardé mon code et j'ai commencé à avoir de sérieux doutes. Je pensais que la complexité du calcul était horrible. J'ai pris une feuille de papier et calculé que le traitement de ces requêtes sur une taille de données attendue prendrait des heures. J'ai donc ajouté un peu de cache ici et là. Et les requêtes fonctionnaient bien.
Gaazkam
3
Vous avez donc fait preuve de diligence raisonnable et vérifié que le problème était réel avant de modifier votre code, qui était initialement le plus clair et le plus intuitif pour vous. Cela signifie que votre optimisation n'était pas prématurée. ;) "Éviter les optimisations prématurément" ne signifie pas "écrire un code inutilement coûteux" - il faut simplement favoriser la simplicité, la lisibilité et la facilité de modification jusqu'à ce qu'un problème de performances ait été identifié. Les commentaires ne sont pas destinés à la discussion, nous pouvons donc discuter si vous souhaitez en parler davantage.
DMGregory
42

note: cette réponse a commencé comme un commentaire sur la réponse de DMGregory, et ne duplique donc pas les très bons arguments qu'il avance.

"Ne serait-il pas incroyablement difficile de changer certaines des structures de base du jeu à la fin, plutôt que de les développer la première fois en tenant compte de la performance?"

Ceci, pour moi, est le noeud de la question.

Lors de la création de votre conception originale, vous devriez essayer de concevoir l' efficacité - au niveau supérieur. C’est moins une optimisation et plus une question de structure.

Exemple:
Vous devez créer un système pour traverser une rivière. Les conceptions évidentes sont un pont ou un ferry, alors que choisissez-vous?
La réponse dépend bien sûr de la taille du passage à niveau et du volume de la circulation. Il ne s’agit pas d’une optimisation, mais bien d’une conception adaptée à votre problème.

Lorsqu'on vous présente des choix de design, vous choisissez celui qui convient le mieux à ce que vous voulez faire.

Alors, disons que notre volume de trafic est assez faible, nous avons donc décidé de construire deux terminaux et d’acheter un ferry pour gérer le trafic. Une belle implémentation simple
Malheureusement, une fois que nous l’avons lancée, nous constatons qu’elle voit plus de trafic que prévu. Nous devons optimiser le ferry! (parce que ça marche, et construire un pont maintenant n'est pas un bon plan)

Les options:

  • Acheter un deuxième ferry (traitement en parallèle)
  • Ajouter un autre pont auto au traversier (compression du trafic)
  • Améliorer le moteur du traversier pour le rendre plus rapide (algorithmes de traitement réécrits)

C’est là que vous devriez essayer de rendre votre conception originale aussi modulaire que possible.
Tout ce qui précède est une optimisation possible, et vous pouvez même faire les trois.
Mais comment faire ces changements sans grands changements structurels?

Si vous avez une conception modulaire avec des interfaces clairement définies, il devrait être simple d’implémenter ces modifications.
Si votre code n'est pas étroitement couplé, les modifications apportées aux modules n'affectent pas la structure environnante.

Jetons un coup d'oeil à l'ajout d'un ferry supplémentaire.
Un «mauvais» programme pourrait être construit autour de l’idée d’un seul ferry, et les états de quai et l’état et la position du ferry seraient regroupés et partagés. Cela sera difficile à modifier pour permettre l’ajout d’un traversier supplémentaire au système.
Une meilleure conception serait d’avoir les quais et le traversier comme entités séparées. Il n'y a pas de couplage étroit entre eux, mais ils ont une interface, où un ferry peut arriver, décharger des passagers, en prendre de nouveaux et partir. Le quai et le ferry partagent uniquement cette interface, ce qui facilite les modifications du système, dans ce cas en ajoutant un second ferry. Le quai ne se soucie pas de ce que sont réellement les ferries, tout ce qui le concerne est que quelque chose (n'importe quoi) utilise son interface.

tl; dr:

  • Essayez de concevoir pour l'efficacité en premier lieu.
  • Quand on vous présente deux choix, vous choisissez le plus efficace.
  • Ecrivez votre code de manière aussi modulaire que possible avec des interfaces bien définies.

Vous pouvez ensuite modifier les mécanismes dans chaque module sans restructurer la base de code complète lorsque vous devez optimiser.

Baldrickk
la source
16
Au début, vous pouvez également implémenter votre ferry au fur IRiverCrossinget à mesure que le volume de trafic est trop important pour le ferry mis en place, implémentez le pont au fur IRiverCrossinget à mesure, puis déposez-le. Le truc est bien sûr de réduire l’API externe du ferry. et la passerelle aux fonctionnalités communes afin qu’elles puissent être représentées par la même interface.
Mr.Mindor
2
Vous pouvez même avoir des tests automatisés écrits pour ces interfaces modulaires, de sorte que vous puissiez refactoriser rapidement sans trop vous soucier de casser quoi que ce soit en dehors du module que vous touchez.
user3067860
2
Très bel exemple de la raison pour laquelle la POO est si importante de nos jours.
Jaime Gallego
1
Vous frappez la bonne raison. Le mantra de Donald Knuth n’est vrai que lorsque la vitesse n’est pas l’une des exigences essentielles et que l’optimisation met l’accent sur la conception principale. Hélas, dans les jeux, la vitesse est souvent au cœur des préoccupations et doit donc être prise en compte dès le début. La préoccupation du PO (et votre réponse) est entièrement justifiée.
Peter A. Schneider
3
@AlexandreVaillancourt au lieu de répondre au titre de la question, j'ai essayé de répondre à ce que je pense être l'élément clé de la question à laquelle on répond effectivement; c'est-à-dire, "pourquoi ne pas optimiser plus tôt si l'optimisation demande plus de travail parce que ma conception est figée" (paraphrasé) . Cette réponse a également commencé comme un commentaire sur la réponse de DMGregory, et s'ajoute à celle-ci, et il est inutile de dupliquer sa réponse.
Baldrickk
24

"Ne pas optimiser au début" ne signifie pas "choisir le pire moyen de faire les choses". Vous devez toujours prendre en compte les conséquences sur les performances (à moins que vous ne fassiez que du prototypage). Le but n'est pas de paralyser d'autres éléments plus importants à ce stade du développement - tels que la flexibilité, la fiabilité, etc. Choisissez des optimisations simples et sûres - choisissez les éléments que vous souhaitez limiter et ceux que vous gardez libres; garder une trace des coûts. Devez-vous utiliser le typage fort? La plupart des jeux ont fonctionné correctement. combien cela vous coûterait-il de supprimer cela si vous trouviez des utilisations intéressantes de la flexibilité pour gamemplay?

Il est beaucoup plus difficile de modifier le code optimisé, en particulier le code "intelligent". C’est toujours un choix qui améliore certaines choses et aggrave d’autres (par exemple, vous pouvez échanger du temps CPU pour utiliser de la mémoire). Lorsque vous faites ce choix, vous devez être conscient de toutes les implications - elles peuvent être désastreuses, mais elles peuvent aussi être utiles.

Par exemple, les commandants Keen, Wolfenstein et Doom ont été construits sur un moteur de rendu optimisé. Chacun avait son "truc" qui permettait au jeu d’exister (des optimisations supplémentaires ont également été développées au fil du temps, mais ce n’est pas important ici). C'est bien . Il est normal d’optimiser fortement le cœur même du jeu, la pensée qui rend le jeu possible; surtout si vous explorez de nouveaux territoires où cette fonctionnalité optimisée vous permet de prendre en compte des conceptions de jeu peu explorées. Les limitations introduites par l'optimisation peuvent également vous donner un jeu intéressant (par exemple, les limites du nombre d'unités dans les jeux RTS ont peut-être été créées pour améliorer les performances, mais elles ont également un effet de gameplay).

Mais notez que dans chacun de ces exemples, le jeu ne pourrait exister sans l'optimisation. Ils n'ont pas commencé avec un moteur «entièrement optimisé» - ils ont commencé par la simple nécessité et ont progressé. Ils développaient de nouvelles technologies et les utilisaient pour créer des jeux amusants. Et les astuces moteur étaient limitées à une partie du code aussi petite que possible - les optimisations plus lourdes n’étaient introduites que lorsque le gameplay était essentiellement terminé ou qu’il permettait à une nouvelle fonctionnalité intéressante de se faire jour.

Maintenant, considérons un jeu que vous voudrez peut-être faire. Y at-il vraiment un miracle technologique qui fait ou défait ce jeu? Peut-être envisagez-vous un jeu en monde ouvert sur un monde infini. Est-ce vraiment la pièce centrale du jeu? Le jeu ne fonctionnerait-il tout simplement pas sans cela? Vous pensez peut-être à un jeu où le terrain est déformable sans limite, avec une géologie réaliste, etc. pouvez-vous le faire fonctionner avec une portée plus petite? Cela fonctionnerait-il en 2D au lieu de 3D? Obtenez quelque chose d'amusant dès que possible - même si les optimisations peuvent vous obliger à retravailler une énorme partie de votre code existant, cela peut en valoir la peine; et vous pourriez même vous rendre compte que rendre les choses plus grandes ne rend pas le jeu meilleur.

Comme exemple de jeu récent avec de nombreuses optimisations, je citerai Factorio. Les courroies sont un élément essentiel du jeu. Elles sont plusieurs milliers et transportent de nombreux morceaux de matériaux individuels tout autour de votre usine. Le jeu a-t-il commencé avec un moteur à courroie fortement optimisé? Non! En fait, la conception de la ceinture originale était presque impossible à optimiser - elle a en quelque sorte simulé physiquement les éléments de la ceinture, ce qui a créé des choses intéressantes que vous pouvez faire (c'est ainsi que vous obtenez un gameplay "émergent" - un gameplay qui surprend concepteur), mais cela signifiait que vous deviez simuler chaque élément de la ceinture. Avec des milliers de courroies, vous obtenez des dizaines de milliers d’éléments simulés physiquement. Même en les supprimant et en les laissant faire le travail, vous réduisez le temps de calcul associé de 95 à 99%. même sans considérer des choses comme la localité de la mémoire. Mais ce n’est utile que de le faire lorsque vous atteignez réellement ces limites.

Presque tout ce qui avait un rapport avec les courroies devait être refait pour permettre leur optimisation. Et les courroies devaient être optimisées, car il fallait beaucoup de courroies pour une grande usine, et les grandes usines sont l'une des attractions du jeu. Après tout, si vous ne pouvez pas avoir de grandes usines, pourquoi avoir un monde infini? C'est drôle, vous devriez demander - les premières versions ne le faisaient pas :) Le jeu a été retravaillé et remodelé de nombreuses fois pour arriver là où il est maintenant - y compris un remake à 100%, quand ils se sont rendus compte que Java n'était pas la solution idéale. jeu comme celui-ci et basculé en C ++. Et cela a bien fonctionné pour Factorio (bien que ce fût une bonne chose, il n’était pas optimisé dès le départ - en particulier s’il s’agissait d’un projet de loisir, qui aurait tout simplement échoué sinon par manque d’intérêt).

Mais la chose est, il y ade nombreuses choses que vous pouvez faire avec une usine à portée limitée - et de nombreux jeux l'ont montré. Les limites peuvent être encore plus stimulantes pour le plaisir que les libertés; Spacechem serait-il plus amusant si les "maps" étaient infinies? Si vous aviez commencé avec des "ceintures" fortement optimisées, vous seriez pratiquement obligé de suivre cette voie; et vous ne pouvez pas explorer d'autres directions de conception (comme voir ce que vous pouvez faire d'intéressant avec des bandes transporteuses simulées par la physique). Vous limitez votre potentiel de conception. Cela ne semble peut-être pas comme cela parce que vous ne voyez pas beaucoup de jeux inachevés, mais le plus difficile est de vous amuser correctement - pour chaque jeu amusant que vous voyez, il y en a probablement des centaines qui ne pouvaient tout simplement pas y arriver et ont été mis au rebut (ou pire, libéré sous forme de désordres horribles). Si l'optimisation vous aide à le faire, allez-y. Si ce n'est pas ... c'est probablement prématuré. Si vous pensez que certains mécanismes de jeu fonctionnent très bien, mais que des optimisations sont nécessaires pour vraiment briller, continuez. Si vous n'avez pas de mécanique intéressante,ne les optimise pas . Trouvez l’amus d’abord - vous constaterez que la plupart des optimisations n’aident pas, et sont souvent désastreuses.

Enfin, vous avez un grand jeu amusant. Est-il judicieux d'optimiser maintenant ? Ha! Ce n'est toujours pas aussi clair que vous pourriez le penser. Y a-t-il quelque chose d' amusantvous pouvez faire à la place? N'oubliez pas que votre temps est encore limité. Tout demande un effort et vous souhaitez concentrer vos efforts là où cela compte le plus. Oui, même si vous créez un "jeu gratuit" ou un jeu "open source". Regardez comment le jeu est joué; remarquez où la performance devient un goulot d'étranglement. Est-ce que l’optimisation de ces lieux rend plus amusant (comme la construction d’usines toujours plus grandes, toujours plus enchevêtrées)? Est-ce que cela vous permet d'attirer plus de joueurs (par exemple avec des ordinateurs plus faibles ou sur différentes plates-formes)? Vous devez toujours prioriser - recherchez l'effort pour obtenir un ratio. Vous trouverez probablement beaucoup de fruits faciles à jouer rien qu'en jouant à votre jeu et en regardant les autres jouer. Mais notez la partie importante - pour y arriver, vous avez besoin d'un jeu . Concentre-toi sur ça.

Cerise sur le gâteau, considérez que l'optimisation ne se termine jamais. Ce n'est pas une tâche avec une petite coche que vous terminez et passez à d'autres tâches. Il y a toujours "une optimisation de plus" que vous pouvez faire, et une grande partie de tout développement consiste à comprendre les priorités. Vous ne faites pas l'optimisation pour des raisons d'optimisation - vous le faites pour atteindre un objectif particulier (par exemple, "200 unités à la fois sur l'écran sur un Pentium à 333 MHz" est un excellent objectif). Ne perdez pas de vue l'objectif terminal simplement parce que vous vous concentrez trop sur les objectifs intermédiaires qui pourraient même ne plus être une condition préalable à l'objectif terminal.

Luaan
la source
Je crois que les développeurs de factorio optimisent à nouveau les courroies de sorte qu’ils ne doivent simuler que les éléments de manière périodique. À tout moment, cela interpole leur position lorsque vous les regardez. Mais ils ne font que cela maintenant que lorsque le jeu entier est efficacement basé autour de la ceinture (et des robots) depuis longtemps, et pas avant que les gens ne commencent à remarquer et à se plaindre de la performance.
Immibis
2
@immibis Exactement. L'améliorer avant que les gens atteignent réellement les limites serait un gaspillage de ressources, qui seraient mieux dépensées ailleurs. Même avec les dernières optimisations, vous ne rencontrerez probablement le problème que pour les méga-usines bien au-delà de la portée du gameplay normal (lancement de la fusée). Mais cela a permis aux nouveaux paramètres de jeu Marathon, qui nécessitent une logistique beaucoup plus lourde. Et encore une fois, ils ont identifié les goulots d'étranglement en obtenant des statistiques de la part de personnes jouant réellement au jeu - environ la moitié des goulots d'étranglement étaient une grosse surprise pour eux.
Luaan
@Fattie Vous comprenez donc la question, mais pas la réponse? Essayez-vous simplement de dire qu'une réponse plus simple est possible (par exemple, "Économie")? Je ne vois pas comment votre commentaire est censé être constructif.
Luaan
2
@Fattie Si vous pensez que la réponse est "Optimisez uniquement une fois que vous savez quel est le goulot d'étranglement", signalez-le comme une réponse. Vous avez déjà passé beaucoup plus de mots qu'il n'en faudrait pour une bonne réponse, alors allez-y. Quel type d'optimisation ne rend pas les choses meilleures et pires? Je n'ai certainement jamais vu un. Ce que je répète sans cesse, c’est que c’est toujours un compromis: un temps qui pourrait être mieux dépensé ailleurs, une complexité qui limite votre flexibilité… Les exemples montrent que «tôt» n’est pas un terme absolu; certaines optimisations sont nécessaires dès le premier jour, alors que d'autres sont dépressives.
Luaan
1
@Fattie "Optimiser seulement une fois que vous savez quel est le goulot d'étranglement", répond-il à "Quand devrais-je optimiser?" et n’est-ce pas une réponse à "Pourquoi est-il si mauvais d’optimiser trop tôt?".
Immibis
10

Beaucoup de réponses semblent se focaliser beaucoup sur l'aspect performance de "l'optimisation", alors que moi-même j'aime bien regarder l'optimisation et toute l'épreuve de l'optimisation trop tôt à un niveau plus abstrait.

Humour moi comme je tente d'élaborer sur mon point de vue avec l'aide de polyominos.

Supposons que nous ayons des limites fixes définies par le framework ou le moteur avec lequel nous travaillons.

entrez la description de l'image ici

Nous procédons ensuite à la création de notre première couche / module du jeu comme suit.

entrez la description de l'image ici

À l'avenir, nous construisons notre deuxième couche / module.

entrez la description de l'image ici

À ce stade, vous remarquerez peut-être qu'il y a un peu d'espace disponible entre les deux modules et nous pourrions être tentés de l'optimiser pour tirer pleinement parti des limites qui nous ont été attribuées.

entrez la description de l'image ici

Parfait, maintenant l’application utilise pleinement les ressources dont nous disposons, l’application est meilleure, non?

Nous procédons à la construction de la troisième couche / module de notre application et nous réalisons soudainement (peut-être même que nous ne pouvions pas prévoir lors de la planification initiale) que la troisième couche / module ne fonctionne pas pour nous.

Nous recherchons une alternative, nous en trouvons une, et à la fin, cela nous oblige également à changer le 2ème module de notre application car il est incompatible avec notre 3ème module nouvellement sélectionné. (Heureusement, c'est un peu compatible avec notre 1er module, nous n'avons donc pas à tout réécrire à partir de zéro.)

Nous avons donc tout mis ensemble

entrez la description de l'image ici

Hmm, pouvez-vous voir ce qui s'est passé?

En optimisant trop tôt, nous avons en fait aggravé la situation en termes d’efficacité, car nous n’avons pas optimisé ce que nous avons finalement obtenu.

Et si nous avions voulu ajouter des modules supplémentaires ou des friandises supplémentaires par la suite, nous n’aurions peut-être plus la capacité de les faire à ce stade.

entrez la description de l'image ici

Et ajuster le niveau le plus bas de notre système n’est plus aussi faisable car il a été enterré sous toutes les autres couches.

Si, toutefois, nous avions choisi d'attendre avec notre envie de l'optimiser immédiatement, nous aurions abouti à quelque chose comme ceci:

entrez la description de l'image ici

Et maintenant, si nous procédons à l'optimisation à ce stade, nous obtenons quelque chose de satisfaisant à examiner.

entrez la description de l'image ici

J'espère qu'au moins certains d'entre vous se sont autant amusés à lire ceci qu'à moi :) et si vous sentez maintenant que vous avez une meilleure compréhension du sujet, tant mieux.

Gecko de plafond
la source
3
Je retire la publicité. Nous ne nous soucions pas de la manière dont vous avez créé les images. la seule partie importante est la supposition que vous avez le droit de les poster.
Gnemlock
2
@Gnemlock assez juste, bien que mon intention ne soit pas orientée vers la publicité, je peux aussi voir comment elle pourrait facilement être mal interprétée en tant que telle, et je conviens que cela n'ajoute rien à la réponse, de sorte qu'elle n'a pas sa place.
Gecko plafond
2
Je pense que cette métaphore visuelle est extrêmement efficace. Excellente approche pour répondre à la question! :)
DMGregory
8

Argent.

Cela revient à cela. Argent. Puisque le temps, c'est de l'argent *, plus vous consacrez de temps à des activités pour lesquelles il n'est pas garanti que vous générerez plus d'argent (vous ne pouvez pas considérer ces activités comme des investissements ), plus vous risquez de perdre de l'argent et moins vous gagnerez d'argent. le jeu.

Voici quelques effets secondaires potentiels de l'optimisation trop tôt et les raisons pour lesquelles vous devriez l'éviter:

  • Vos collègues vous détestent parce que vous jouez dans votre bac à sable avec vos jouets alors qu'ils travaillent dur pour obtenir des fonctionnalités.
  • Les retards déplaisent aux échelons supérieurs et obligent l’équipe à rater les dates de livraison, ce qui entraîne la sortie du jeu au printemps au lieu d’avant les fêtes de fin d’année, ce qui fait que le jeu ne se vend pas assez. Et pour cette raison, le siège décide de fermer le studio, vous rendant effectivement sans emploi. Et pas de travail, pas d'argent. (Et comme personne ne vous aime parce que vous avez passé trop de temps à l'optimisation précoce, personne ne veut écrire une critique positive de votre travail pour vous sur LinkedIn, ce qui vous gardera sans argent plus longtemps.)

* D'autres réponses ont assez bien mis en évidence la partie "temps"


En guise de remarque, en général , l’expérience permet de déterminer ce qui est optimisation prématurée et ce qui n’est pas prématuré et ce qui a une valeur pour l’entreprise et ce qui n’en a pas.

Par exemple, si vous avez travaillé sur le jeu A et si, à la fin du projet, vous vous rendez compte que la fonctionnalité XYZ était particulièrement lourde dans votre boucle de jeu, vous commencez à travailler sur le jeu B qui possède exactement la même fonctionnalité réécrire la fonctionnalité et l’optimiser dès le départ n’est pas vraiment une optimisation prématurée, car vous savez que ce sera un goulot d’étranglement si rien n’est fait.

Alexandre Vaillancourt
la source
1
@JBentley c'est un point valable. Cependant, il y a une réponse conséquente au "pourquoi" en tant qu'implication directe de l'expérience acquise. Ainsi, 1) l'optimisation précoce peut entraîner une perte de temps sur des parties du code qui n'ont pas d'incidence sur le temps d'exécution moyen (compte tenu de l'expérience, vous devez savoir quelles constructions de code sont candidates aux meilleures pratiques d'optimisation) 2) l'optimisation précoce peut rendre le code plus difficile maintenir en raison des restrictions de conception imposées sur certains systèmes. Vous risquez donc de gagner trop peu en échange de cycles de développement plus longs / de codes fastidieux à maintenir.
Teodron
3
@JBentley Considérez ceci comme un addendum à la réponse de DMGregory.
Alexandre Vaillancourt
1
Cela semblerait être la seule réponse valable ici. La question est une tautologie. Vous pourriez aussi bien demander: "Alors pourquoi, en fait, voulez-vous qu'un jeu gagne plus plutôt que moins d'argent sur les app stores?" Comment pouvez-vous répondre à cela?
Fattie
@Fattie C'est bien d'avoir ce genre de perspective dans une réponse. Mais dire que c'est la seule réponse qui vaille la peine, c'est de réduire la portée de la question de manière déraisonnable. Vous supposez, par exemple, que les seuls jeux créés appartiennent à des organisations à but lucratif (ce n'est manifestement pas vrai). Vous supposez également qu'il est évident pour le PO que l'optimisation précoce entraîne plus de temps (et donc plus d'argent si on parle d'entreprise). En réalité, la question du PO montre qu'il n'est pas sûr de cela.
JBentley
6

L'optimisation est, par définition, le processus d'augmentation de l'efficacité d'une solution jusqu'au point où elle perd de son efficacité. Ce processus implique alors une réduction de l'espace de la solution.

À un stade précoce du développement logiciel, il peut toujours y avoir des "exigences cachées": si vous réduisez trop l’espace de votre solution, vous risquez de vous retrouver dans une situation dans laquelle vous ne pourrez pas satisfaire à une "exigence cachée" lorsqu’elle apparaîtra. à un stade ultérieur du développement, vous obligeant alors à modifier l’architecture en ajoutant de cette manière une instabilité et un tas de comportements indésirables.

L'idée est alors de faire fonctionner la solution entière et ensuite seulement, lorsque toutes les exigences sont définies et implémentées, resserrer le code. Vous verrez alors que de nombreuses optimisations que vous auriez légèrement mises en œuvre à la fois lors du codage, ne sont plus réalisables en raison de l’interaction avec les dernières exigences.

L'espace réel de la solution est toujours plus grand que celui auquel nous nous attendions au départ car nous ne pouvons pas avoir une connaissance parfaite d'un système très complexe.

Faites-le fonctionner en premier. Puis serrez les cordes.

Earendel
la source
2
Je pense que le mot «efficacité» n’est pas le mot que vous recherchez, mais signifie «le pouvoir de produire un effet». L’optimisation consiste donc, dans l’ensemble, à accroître l’ efficacité. Allez-vous pour une version spécifique de l'efficacité? (Pourriez-vous créer un lien vers ce site?) Voulez-vous plutôt parler de flexibilité?
doppelgreener
2
@doppelgreener Cela signifie que vous rendez la solution plus efficace jusqu'à ce qu'elle cesse de produire les effets souhaités ...
immibis
1
"Faites-le fonctionner en premier. Serrez ensuite les cordes." - Cela doit valoir autant que le reste de la réponse combinée. Et pour ne pas dire que les autres trucs n'étaient pas bons.
ebyrob
1
@ebyrob: il y a un autre dicton qui dit: "Faites que ça marche, fassiez comme
ninjalj
@ninjalj C'est un bon exemple aussi. Bien sûr, mon patron me dit toujours: "Ne vous précipitez pas, corrigez-vous." Donc, je ne sais pas si ce que vous dites est aussi universel que l'affiche originale demande plus de détails.
ebyrob
2

En résumé, très souvent, l'optimisation précoce entraîne un gaspillage d'efforts si vous voulez changer les choses plus tard, puis il s'avère que vous avez optimisé les structures de code facilement modifiables en un niveau beaucoup plus bas, et vous devez maintenant le ramener à un niveau élevé. approche par niveau et d’optimiser à nouveau le résultat.

Il s'agit d'une erreur courante pour les développeurs débutants qui aiment se concentrer sur le plaisir "d'avoir fait un travail utile", comme l'optimisation, sans se demander si le moment est propice pour le faire. En acquérant de l'expérience en programmant de gros projets comme des jeux, vous saurez quand il sera nécessaire d'optimiser la base de code existante et quand il sera trop tôt. N'ayez pas peur de faire cette erreur, vous ne pourrez que tirer profit de son apprentissage.

En général, n'optimisez que si vous ne pouvez vraiment pas travailler avec la construction de développement dès maintenant. Par exemple, si vous créez et supprimez des millions d'objets 60 fois par seconde.

Donc, je dirais qu’il est bon, en termes d’apprentissage, d’optimiser au début quelques fois: p

utilisateur1306322
la source
2

L'optimisation vise à optimiser le fonctionnement de l'ordinateur sur le code, tandis que le développement nécessite que le programmeur fonctionne mieux sur le code.

L'optimisation ne fait pas ressortir les idées. Cela fait moins travailler l'ordinateur et le programmeur davantage.

Bien sûr, il existe différentes catégories, comme pour concevoir une voiture. Il n’ya rien de mal à optimiser un moteur avant de construire votre premier châssis, mais l’optimiser avant que vous ne connaissiez la forme du moteur risque de vous faire perdre du temps. La modularité et les spécifications peuvent permettre à un certain nombre d’endroits d’être optimisés avant même que le produit ne soit assemblé.

utilisateur101307
la source
Cela serait amélioré en dirigeant avec autre chose que de définir l'optimisation et en parlant de la situation pratique dans le développement de jeux plutôt que de faire des analogies sur les voitures.
doppelgreener
Une réponse parfaite à une question tautologique.
Fattie
2

Je ne suis absolument pas d'accord avec toutes ces affirmations selon lesquelles le code ne devrait pas être optimisé au tout début. Cela dépend de votre stade. Si c'est MVP - prototype et que vous essayez simplement de regarder le jeu qui dure 1 à 2 semaines, vous êtes prêt à réécrire tout ce que vous avez déjà écrit. Oui, l'optimisation n'a pas d'importance. Mais si vous travaillez déjà sur un jeu dont vous savez qu'il sortira, le code devrait toujours être optimisé. Les histoires que les gens racontent sur les nouvelles fonctionnalités et les choses qui pourraient être ajoutées sont des idées fausses. C'est une architecture de code mal conçue plutôt qu'un code optimisé. Vous n'avez pas besoin de réécrire quoi que ce soit pour ajouter de nouveaux éléments si vous avez une bonne conception de code.

Par exemple, si vous avez un algorithme A * pathfinding, ne serait-il pas préférable de l'écrire de la manière la plus optimale possible? Plutôt que de changer plus tard la moitié du code que vous avez parce que vous avez dû apporter des modifications à l'algorithme, car il a maintenant besoin d'une autre méthode d'appels et de rappels? Et si vous avez déjà un code optimisé dès le départ, vous gagnerez beaucoup de temps. Parce que vous pouvez dessiner vous-même les relations entre les objets et leur interaction, au lieu de créer aveuglément des tonnes de nouveaux scripts et d'établir toutes les connexions immédiatement - cela conduit à un code de sphagetti peu clair.

La dernière chose que je veux ajouter est que plus tard, même si vous ne voulez plus créer le jeu, vous disposez de votre algorithme A * optimisé que vous pourrez utiliser pour vos prochains jeux. Réutilisabilité. Par exemple, de nombreux jeux ont un inventaire, une recherche de chemin, une génération de procédures, des interactions entre NPC, un système de combat, une IA, une interaction d’interface, une gestion des entrées. Maintenant, vous devriez vous demander: "Combien de fois ai-je réécrit ces éléments à partir de zéro?" Ils sont 70-80% du jeu. Avez-vous vraiment besoin de les réécrire tout le temps? Et si elles ne sont pas optimisées?

Lune candidate _Max_
la source
5
Si un code * doit démarrer optimisé, dans quelle mesure est-il optimisé? Est-ce que vous codez les choses en assemblée avant de faire des repères? Je pense que, de manière générale, les travaux non micro-triviaux sur les micro-optimisations devraient être laissés jusqu'à ce que des points de repère aient été établis. Le compilateur optimiseur pourrait faire un meilleur travail que vous lors de la micro-optimisation et est beaucoup moins cher.
mardi
@gmatht Well A * peut être différent, comme je l'ai dit, son design peut être médiocre et il ne fonctionne pas très bien. Mais il peut être multithread, basé sur le tas de Fibonacci, avoir certaines prédictions, divisées en morceaux. Si nous parlons de pathfinding, nous pouvons ajouter Flow Field à mélanger avec A *. Aussi bien lisser, multi hauteur. Peut-être que A * n’est pas le meilleur exemple, mais comme je l’ai dit, les optimisations n’ont rien à voir avec la modification du code. Le développeur modifie le code car il était mal conçu. Par exemple, il n’a pas suivi SOLID comme raison. bien écrit, vous n’avez plus besoin de l’écrire.
Candid Moon _Max_
@gmatht Les micro-optimisations ne sont pas réellement le problème. Je pense que OP signifie plus le moyen le plus efficace et le plus efficace de calculer le comportement, le shader ou toute autre chose de l'IA.
Candid Moon _Max_
Si vous savez comment écrire ces choses efficacement, je ne vois pas le problème le faire. Cela prendra le même temps, voire moins. Cela dépend plus de l'expérience des développeurs. En tant que programmeur, si je connaissais une meilleure solution, je n’écrirais pas de merde. Si je sais écrire le tas de Fibonacci, je n’utiliserai ni Liste ni tri pour obtenir les valeurs min ou max. Bien sûr, il faudra plus de temps et d’efforts pour l’écrire, au lieu d’utiliser List.Sort (); , mais que faire si j’en ai déjà un réutilisable?
Candid Moon _Max_
2
@CandidMoon Je ne suis pas d'accord avec "Cela prendra le même temps, voire moins." écrire du code efficace. Peut-être faudrait-il prendre le même temps pour écrire du code qui ne soit pas manifestement inefficace, mais lorsque votre notion «d'efficacité» signifierait tenir compte de la contention dans le cache, en ajoutant du multithreading, en utilisant des éléments intrinsèques spécifiques à la CPU disponibles sur certaines CPU uniquement, des algorithmes de commutation pour les grands N dus à O (N log N) vs O (N) - ce genre de chose est dure et sujette aux erreurs et prend beaucoup plus de temps que la simple implémentation. Vous ne le faites que lorsque vous savez que cela aura un effet important sur le résultat final.
Michael Anderson