Czy przedwczesna optymalizacja naprawdę jest źródłem wszelkiego zła?


215

Mój kolega dzisiaj zaangażował klasę o nazwie ThreadLocalFormat, która zasadniczo przeniosła instancje klas formatu Java do lokalnego wątku, ponieważ nie są one bezpieczne dla wątków i „stosunkowo drogie” do utworzenia. Napisałem szybki test i obliczyłem, że mogę stworzyć 200 000 instancji na sekundę, zapytałem go, czy tworzy tyle, na które odpowiedział „nigdzie w pobliżu tak wielu”. Jest świetnym programistą i wszyscy w zespole są wysoko wykwalifikowani, więc nie mamy problemu ze zrozumieniem powstałego kodu, ale najwyraźniej chodziło o optymalizację tam, gdzie nie ma prawdziwej potrzeby. Wycofał kod na moją prośbę. Co myślisz? Czy to przypadek „przedwczesnej optymalizacji” i jak źle jest naprawdę?


22
Myślę, że musisz rozróżnić przedwczesną optymalizację i niepotrzebną optymalizację. Przedwczesne dla mnie sugeruje „zbyt wcześnie w cyklu życia”, co jest niepotrzebne, sugeruje, że „nie wnosi znaczącej wartości”. IMO, wymóg późnej optymalizacji oznacza tandetny projekt.

109
Tak, ale zło jest wielomianem i ma wiele korzeni, niektóre z nich są złożone.
dan_waterworth

7
Powinieneś wziąć pod uwagę, że Knuth napisał to w 1974 roku. W latach siedemdziesiątych pisanie wolnych programów nie było tak łatwe, jak obecnie. Pisał z myślą o Pascalu, a nie z Javą ani PHP.
ceving

4
Nie. Źródłem wszelkiego zła jest chciwość.
Tulains Córdova,

12
@ceving W latach 70. pisanie wolnych programów było tak proste jak dzisiaj. Jeśli wybierzesz zły algorytm lub niewłaściwą strukturę danych, BAM! Słaba wydajność w każdym miejscu. Można się kłócić na odwrót. Dzisiaj jest o wiele więcej narzędzi i powinno być niewybaczalne, że programista nadal pisze oprogramowanie, które cierpi z powodu najbardziej podstawowej operacji składowania. Równoległość stała się prawie towarem i nadal cierpimy. Niska wydajność nie może być obwiniana za język, narzędzie, procesor lub pamięć. To delikatna równowaga tak wielu rzeczy, dlatego prawie niemożliwe jest wczesne zoptymalizowanie.
Alex

Odpowiedzi:


322

Należy pamiętać o pełnej wycenie:

Powinniśmy zapomnieć o małej wydajności, powiedzmy około 97% czasu: przedwczesna optymalizacja jest źródłem wszelkiego zła. Nie powinniśmy jednak tracić naszych szans w tak krytycznych 3%.

Oznacza to, że przy braku mierzonych problemów z wydajnością nie należy optymalizować, ponieważ uważasz , że uzyskasz wzrost wydajności. Istnieją oczywiste optymalizacje (takie jak nie wykonywanie konkatenacji łańcuchów w ciasnej pętli), ale należy unikać wszystkiego, co nie jest trywialnie optymalizacją, dopóki nie będzie można tego zmierzyć.

Największe problemy związane z „przedwczesną optymalizacją” polegają na tym, że może ona wprowadzać nieoczekiwane błędy i powodować ogromne straty czasu.


7
Będąc z Donalda Knutha, nie byłbym zaskoczony, gdyby miał jakieś dowody na poparcie tego. BTW, Src: Programowanie strukturalne za pomocą go to Statement, ACM Journal Computing Surveys, tom 6, nr 4, grudzień 1974. str. 268. citeseerx.ist.psu.edu/viewdoc/...
mctylr

28
... Dobry programista nie zostanie uśpiony przez takie rozumowanie, rozsądnie przyjrzy się krytycznemu kodowi; ale dopiero po zidentyfikowaniu tego kodu (reszta pełniejszej oferty)
mctylr

21
Miałem dziś 20-krotnego użytkownika powtórzeń, który powiedział mi, że użycie HashSetzamiast zamiast Listprzedwczesnej optymalizacji. Przypadek użycia, o którym mowa, był zbiorem zainicjowanym statycznie, którego jedynym celem było służyć jako tabela przeglądowa. Nie sądzę, że się mylę, mówiąc, że istnieje rozróżnienie w wyborze odpowiedniego narzędzia do pracy w porównaniu z przedwczesną optymalizacją. Myślę, że twój post potwierdza tę filozofię: There are obvious optimizations...anything that isn't trivially clear optimization should be avoided until it can be measured.optymalizacja HashSet została dokładnie zmierzona i udokumentowana.
zmiażdżyć

9
@crush: tak: Setjest również bardziej semantycznie poprawny i zawiera więcej informacji niż informacje List, więc jest w tym coś więcej niż aspekt optymalizacji.
Erik Allik

7
Chciałbym dodać, że przedwczesnej optymalizacji nie należy mylić z projektowaniem całej architektury aplikacji tak, aby działała ogólnie szybko, skalowała się i była łatwa do optymalizacji.
Erik Allik

111

Przedwczesne mikrooptymalizacje są źródłem wszelkiego zła, ponieważ mikrooptymalizacje pomijają kontekst. Prawie nigdy nie zachowują się tak, jak się spodziewają.

Jakie są dobre wczesne optymalizacje w kolejności ważności:

  • Optymalizacje architektoniczne (struktura aplikacji, sposób jej komponowania i warstw)
  • Optymalizacje przepływu danych (wewnątrz i na zewnątrz aplikacji)

Niektóre optymalizacje w średnim cyklu rozwojowym:

  • Struktury danych, wprowadzaj nowe struktury danych, które mają lepszą wydajność lub w razie potrzeby zmniejszają koszty ogólne
  • Algorytmy (teraz jest dobry moment, aby zacząć decydować między Quicksort3 a Heapsort ;-))

Niektóre optymalizacje zakończenia cyklu rozwojowego

  • Znajdowanie hotpotów kodu (ciasne pętle, które należy zoptymalizować)
  • Optymalizacje oparte na profilowaniu części obliczeniowych kodu
  • Mikrooptymalizacje można teraz wykonać tak, jak w kontekście aplikacji, a ich wpływ można zmierzyć poprawnie.

Nie wszystkie wczesne optymalizacje są złe, mikrooptymalizacje są złe, jeśli są wykonywane w niewłaściwym czasie w cyklu rozwojowym , ponieważ mogą negatywnie wpływać na architekturę, mogą negatywnie wpływać na początkową produktywność, mogą mieć nieistotny wpływ na wydajność lub nawet mieć szkodliwy efekt na końcu rozwoju z powodu różnych warunków środowiskowych.

Jeśli wydajność ma znaczenie (i zawsze powinna być), zawsze myśl na dużą skalę . Wydajność jest szersza i nie dotyczy takich rzeczy: czy powinienem używać int czy long ? Przejdź do góry w dół podczas pracy z wydajnością zamiast od dołu do góry .


„Optymalizacja: Twój najgorszy wróg”, Joseph M. Newcomer: flounder.com/optimization.htm
Ron Ruble

53

optymalizacja bez pierwszego pomiaru jest prawie zawsze przedwczesna.

Uważam, że tak jest w tym przypadku, a także w przypadku ogólnym.


Tutaj tutaj! Nieprzemyślana optymalizacja uniemożliwia utrzymanie kodu i często jest przyczyną problemów z wydajnością. np. tworzysz program wielowątkowy, ponieważ wyobrażasz sobie, że może to poprawić wydajność, ale prawdziwym rozwiązaniem byłoby wiele procesów, które są teraz zbyt skomplikowane, aby je wdrożyć.
James Anderson

chyba że jest to udokumentowane.
nawfal

Tak. kompletnie się zgadzam. Najpierw trzeba to zmierzyć. W żaden sposób nie wiesz, gdzie są wąskie gardła, dopóki nie przetestujesz czegoś od końca do końca i nie zmierzysz każdego z kroków.
Oliver Watkins

Pomiary mogą kłamać. Widziałem, jak doświadczeni specjaliści spędzają tygodnie czytając ślady i biegając profile, by uderzyć w ścianę, gdzie myśleli, że nie ma nic więcej do zyskania. Następnie przeczytałem cały kod i po kilku godzinach wprowadziłem kilka holistycznych zmian, aby uzyskać 10-krotną poprawę. Profile nie wykazały ścieżek dostępu, ponieważ cały kod został źle zaprojektowany. Widziałem także, że profilerzy twierdzą, że są gorące ścieżki tam, gdzie nie powinno ich być. Osoba „mierząca” zoptymalizowałaby ścieżkę dostępu, ale powinna była zdawać sobie sprawę, że ścieżka dostępu jest objawem innego złego kodu.
Bengie,

42

Optymalizacja jest „zła”, jeśli powoduje:

  • mniej przejrzysty kod
  • znacznie więcej kodu
  • mniej bezpieczny kod
  • zmarnowany czas programisty

W twoim przypadku wydaje się, że trochę czasu programisty już spędzono, kod nie był zbyt skomplikowany (zgadnij z twojego komentarza, że ​​wszyscy w zespole byliby w stanie zrozumieć), a kod jest nieco bardziej przyszłościowy (jest wątek bezpieczny teraz, jeśli zrozumiałem twój opis). Brzmi jak tylko trochę zła. :)


4
Tylko jeśli koszt, wyrażony w punktach, jest większy niż dostarczona zamortyzowana wartość. Często złożoność wprowadza wartość, a w takich przypadkach można ją kapsułkować tak, aby spełniała kryteria. Jest również ponownie wykorzystywany i nadal zapewnia większą wartość.

1
Te dwa pierwsze punkty są dla mnie najważniejsze, a czwarty punkt jest negatywną konsekwencją przedwczesnej optymalizacji. W szczególności jest to czerwona flaga, ilekroć widzę kogoś, kto ponownie implementuje funkcje ze standardowej biblioteki. Na przykład widziałem kiedyś, jak ktoś implementuje niestandardowe procedury manipulacji ciągami, ponieważ martwił się, że wbudowane polecenia są zbyt wolne.
jhocking

8
Zapewnienie bezpieczeństwa wątku kodu nie jest optymalizacją.
mattnz

38

Dziwi mnie, że to pytanie ma 5 lat, a jednak nikt nie opublikował więcej tego, co powiedział Knuth, niż kilka zdań. Kilka akapitów otaczających słynny cytat wyjaśnia to całkiem dobrze. Cytowany artykuł nazywa się „ Programowanie strukturalne z przejściem do instrukcji ” i choć ma prawie 40 lat, dotyczy kontrowersji i ruchu programowego, który już nie istnieje i zawiera przykłady języków programowania, których wielu ludzi nigdy nie znało słyszałem, że zaskakująco duża część tego, co zostało powiedziane, nadal obowiązuje.

Oto większy cytat (ze strony 8 pliku pdf, strona 268 w oryginale):

Poprawa prędkości z przykładu 2 do przykładu 2a wynosi tylko około 12% i wiele osób uznałoby to za nieistotne. Konwencjonalna mądrość podzielana przez wielu współczesnych inżynierów oprogramowania wymaga ignorowania wydajności w małych; ale uważam, że jest to po prostu nadmierna reakcja na nadużycia, które widzą, że są praktykowane przez prozaicznych i głupich programistów, którzy nie mogą debugować ani utrzymywać swoich „zoptymalizowanych” programów. W uznanych dyscyplinach inżynierskich poprawa o 12%, łatwo osiągalna, nigdy nie jest uważana za marginalną; i uważam, że ten sam punkt widzenia powinien przeważać w inżynierii oprogramowania. Oczywiście nie zawracałbym sobie głowy robieniem takich optymalizacji przy jednorazowej pracy, ale gdy chodzi o przygotowanie programów wysokiej jakości, nie chcę ograniczać się do narzędzi, które odmawiają mi takiej wydajności.

Nie ulega wątpliwości, że graal wydajności prowadzi do nadużyć. Programiści tracą ogromną ilość czasu na myślenie lub martwienie się o szybkość niekrytycznych części swoich programów, a te próby wydajności mają silny negatywny wpływ na debugowanie i konserwację. My powinniśmy zapomnieć o małych wydajności, powiedzmy około 97% czasu: przedwczesny optymalizacji jest korzeniem wszelkiego zła.

Nie powinniśmy jednak tracić naszych szans w tak krytycznych 3%. Dobry programista nie uśpi się na skutek takiego rozumowania, rozsądnie przyjrzy się krytycznemu kodowi; ale dopiero po zidentyfikowaniu tego kodu. Często błędem jest osądzanie z góry, które części programu są naprawdę krytyczne, ponieważ uniwersalne doświadczenie programistów używających narzędzi pomiarowych polegało na tym, że ich intuicyjne domysły zawodzą.

Kolejny dobry kawałek z poprzedniej strony:

Mój własny styl programowania zmienił się oczywiście w ciągu ostatniej dekady, zgodnie z trendami tamtych czasów (np. Nie jestem już tak trudny i używam mniej przejść do), ale zasadnicza zmiana w moim stylu była spowodowana do tego zjawiska wewnętrznej pętli. Patrzę teraz niezwykle żółtawym okiem na każdą operację w krytycznej pętli wewnętrznej, starając się zmodyfikować mój program i strukturę danych (jak w przypadku zmiany z przykładu 1 na przykład 2), aby niektóre operacje mogły zostać wyeliminowane. Powody takiego podejścia są następujące: a) nie trwa długo, ponieważ pętla wewnętrzna jest krótka; b) wypłata jest realna; oraz c) mogę sobie pozwolić na mniejszą wydajność w innych częściach moich programów, które w związku z tym są bardziej czytelne, łatwiejsze do napisania i debugowania.


20

Często widziałem ten cytat usprawiedliwiający oczywisty zły kod lub kod, który, choć nie został zmierzony jego wydajności, prawdopodobnie mógłby zostać przyspieszony dość łatwo, bez zwiększania rozmiaru kodu lub pogarszania jego czytelności.

Ogólnie uważam, że wczesne mikrooptymalizacje mogą być złym pomysłem. Jednak optymalizacje makr (takie jak wybór algorytmu O (log N) zamiast O (N ^ 2)) są często opłacalne i powinny być wykonane wcześnie, ponieważ pisanie algorytmu O (N ^ 2) i marnotrawstwem może być następnie wyrzuć to całkowicie na korzyść podejścia O (log N).

Zauważ, że słowa mogą być następujące : jeśli algorytm O (N ^ 2) jest prosty i łatwy do napisania, możesz go wyrzucić później bez większego poczucia winy, jeśli okaże się on zbyt wolny. Ale jeśli oba algorytmy są podobnie złożone lub jeśli oczekiwane obciążenie jest tak duże, że wiesz, że będziesz potrzebować szybszego, wtedy optymalizacja na wczesnym etapie jest rozsądną decyzją inżynieryjną, która zmniejszy całkowite obciążenie w dłuższej perspektywie.

Ogólnie rzecz biorąc, myślę, że właściwym podejściem jest sprawdzenie, jakie masz opcje, zanim zaczniesz pisać kod i świadomie wybranie najlepszego algorytmu dla twojej sytuacji. Co najważniejsze, zwrot „przedwczesna optymalizacja jest źródłem wszelkiego zła” nie usprawiedliwia ignorancji. Programiści powinni mieć ogólne wyobrażenie o koszcie typowych operacji; powinni wiedzieć na przykład

  • że ciągi kosztują więcej niż liczby
  • języki dynamiczne są znacznie wolniejsze niż języki o typie statycznym
  • zalety list tablic / wektorów w porównaniu z listami połączonymi i odwrotnie
  • kiedy korzystać z tablicy mieszającej, kiedy korzystać z posortowanej mapy, a kiedy ze stosu
  • że (jeśli działają z urządzeniami mobilnymi) „double” i „int” mają podobną wydajność na komputerach stacjonarnych (FP może być nawet szybszy), ale „double” może być sto razy wolniejszy na niższych urządzeniach mobilnych bez FPU;
  • że przesyłanie danych przez Internet jest wolniejsze niż dostęp do dysku twardego, dyski twarde są znacznie wolniejsze niż pamięć RAM, pamięć RAM jest znacznie wolniejsza niż pamięć podręczna L1 i rejestry, a operacje internetowe mogą blokować się na czas nieokreślony (i w dowolnym momencie mogą ulec awarii).

Ponadto programiści powinni zapoznać się z zestawem struktur danych i algorytmów, aby mogli łatwo korzystać z odpowiednich narzędzi do danego zadania.

Posiadanie dużej wiedzy i osobistego zestawu narzędzi umożliwia optymalizację niemal bez wysiłku. Wkładanie wielu wysiłków w optymalizację, która może być niepotrzebna, jest złem (i przyznaję, że wpadłem w tę pułapkę więcej niż raz). Ale jeśli optymalizacja jest tak prosta, jak wybranie zbioru / tablicy mieszającej zamiast tablicy lub przechowywanie listy liczb w podwójnym [] zamiast ciągu [], to dlaczego nie? Może nie zgadzam się z Knuthem tutaj, nie jestem pewien, ale myślę, że mówił o optymalizacji niskiego poziomu, podczas gdy mówię o optymalizacji wysokiego poziomu.

Pamiętaj, że ten cytat pochodzi z 1974 roku. W 1974 roku komputery działały wolno, a moc obliczeniowa była droga, co dało niektórym programistom tendencję do nadmiernej optymalizacji, linia po linii. Myślę, że właśnie temu naciskał Knuth. Nie mówił „wcale nie przejmuj się wydajnością”, ponieważ w 1974 roku to byłaby szalona rozmowa. Knuth wyjaśniał, jak zoptymalizować; w skrócie, należy skupić się tylko na wąskich gardłach, a zanim to zrobisz, musisz wykonać pomiary, aby znaleźć wąskie gardła.

Zauważ, że nie możesz znaleźć wąskich gardeł, dopóki nie napiszesz programu do pomiaru, co oznacza, że ​​niektóre decyzje dotyczące wydajności muszą zostać podjęte, zanim cokolwiek zostanie zmierzone. Czasami decyzje te trudno zmienić, jeśli się pomylisz. Z tego powodu dobrze jest mieć ogólny obraz tego, co kosztuje, abyś mógł podejmować rozsądne decyzje, gdy żadne twarde dane nie są dostępne.

To, jak wcześnie zoptymalizować i jak bardzo martwić się o wydajność, zależy od zadania. Pisząc skrypty, które uruchomisz tylko kilka razy, martwienie się o wydajność zwykle jest kompletną stratą czasu. Ale jeśli pracujesz dla Microsoft lub Oracle i pracujesz nad biblioteką, z której tysiące innych programistów będą korzystać na tysiące różnych sposobów, może opłacić się optymalizacja, abyś mógł pokryć wszystkie różnorodne efektywnie wykorzystuj skrzynki. Mimo to potrzeba wydajności musi być zawsze zrównoważona z potrzebą czytelności, łatwości konserwacji, elegancji, rozszerzalności i tak dalej.


2
Amen. Przedwczesna optymalizacja jest obecnie zbyt daleko posunięta przez ludzi, którzy próbują uzasadnić użycie niewłaściwego narzędzia do pracy. Jeśli znasz odpowiednie narzędzie do pracy z wyprzedzeniem, nie ma usprawiedliwienia, aby go nie używać.
zmiażdżyć

13

Osobiście, jak opisano w poprzednim wątku , nie sądzę, aby wczesna optymalizacja była zła w sytuacjach, w których wiesz, że napotkasz problemy z wydajnością. Na przykład piszę oprogramowanie do modelowania i analizy powierzchni, w którym regularnie mam do czynienia z dziesiątkami milionów podmiotów. Planowanie optymalnej wydajności na etapie projektowania jest znacznie lepsze niż późna optymalizacja słabej konstrukcji.

Inną kwestią do rozważenia jest skalowanie aplikacji w przyszłości. Jeśli uważasz, że Twój kod będzie miał długą żywotność, dobrym pomysłem jest również optymalizacja wydajności na etapie projektowania.

Z mojego doświadczenia wynika, że ​​późna optymalizacja zapewnia skromne nagrody w wysokiej cenie. Optymalizacja na etapie projektowania, poprzez wybór algorytmu i dostosowanie, jest znacznie lepsza. W zależności od narzędzia do profilowania, aby zrozumieć, jak działa Twój kod, nie jest to świetny sposób na uzyskanie kodu o wysokiej wydajności, powinieneś o tym wiedzieć wcześniej.


To jest z pewnością poprawne. Myślę, że przedwczesna optymalizacja ma miejsce, gdy kod staje się bardziej złożony / trudny do zrozumienia dla niejasnych korzyści, w sposób, który ma jedynie wpływ lokalny (projekt ma wpływ globalny).
Paul de Vrieze

2
Chodzi o definicje. Optymalizację projektuję i piszę, by optymalnie działać. Większość tutaj wydaje się traktować go jako włamanie się do kodu, gdy tylko okaże się, że nie jest on wystarczająco szybki ani wydajny. Dużo czasu spędzam na optymalizacji, zwykle podczas projektowania.

3
Zoptymalizuj projekt na początku, Zoptymalizuj kod na końcu.
BCS,

W twoim przypadku masz rację, jednak dla większości programistów są przekonani, że napotkają problemy z wydajnością, ale w rzeczywistości nigdy nie będą. Wiele osób martwi się wydajnością w kontaktach z 1000 jednostek, gdy podstawowy test danych wykazałby, że wydajność jest w porządku, dopóki nie osiągną 1000000 jednostek.
Toby Allen

1
„Planowanie optymalnej wydajności na etapie projektowania jest znacznie lepsze niż późna optymalizacja słabego projektu”, a „późna optymalizacja zapewnia skromne nagrody w wysokiej cenie” bardzo dobrze ujęte! Prawdopodobnie nie jest to prawdą w przypadku 97% wszystkich wyprodukowanych systemów, ale dotyczy to wielu - niepokojąco wielu - systemów.
Olof Forshell

10

W rzeczywistości dowiedziałem się, że przedwczesna nieoptymalizacja jest częściej źródłem wszelkiego zła.

Kiedy ludzie piszą oprogramowanie, początkowo będą mieć problemy, takie jak niestabilność, ograniczone funkcje, zła użyteczność i zła wydajność. Wszystkie te zwykle są naprawiane, gdy oprogramowanie dojrzewa.

Wszystkie z wyjątkiem wydajności. Wydaje się, że nikomu nie zależy na wydajności. Powód jest prosty: jeśli oprogramowanie ulegnie awarii, ktoś naprawi błąd i to wszystko, jeśli brakuje funkcji, ktoś ją zaimplementuje i zrobi, jeśli oprogramowanie ma niską wydajność, w wielu przypadkach nie wynika to z braku mikrooptymalizacji, ale z powodu złego projektu i nikt nie będzie dotykać projektu oprogramowania. ZAWSZE.

Spójrz na Bochsa. Jest powolny jak diabli. Czy kiedykolwiek będzie szybciej? Może, ale tylko w zakresie kilku procent. Nigdy nie uzyska wydajności porównywalnej z oprogramowaniem do wirtualizacji, takim jak VMWare lub VBox, a nawet QEMU. Ponieważ z założenia jest powolny!

Jeśli problem oprogramowania polega na tym, że jest on powolny, to dlatego, że jest on BARDZO powolny i można to naprawić tylko poprzez poprawę wydajności o wiele. + 10% po prostu nie przyspieszy działania wolnego oprogramowania. Późniejsze optymalizacje zwykle nie przyniosą więcej niż 10%.

Więc jeśli wydajność jest JAKIEKOLWIEK ważna dla twojego oprogramowania, powinieneś wziąć to pod uwagę od samego początku, projektując je, zamiast myśleć „och tak, jest powolne, ale możemy to poprawić później”. Ponieważ nie możesz!

Wiem, że tak naprawdę nie pasuje to do twojego konkretnego przypadku, ale odpowiada na ogólne pytanie: „Czy przedwczesna optymalizacja naprawdę jest źródłem wszelkiego zła?” - z wyraźnym NIE.

Każda optymalizacja, jak każda funkcja itp. Musi być starannie zaprojektowana i starannie wdrożona. Obejmuje to właściwą ocenę kosztów i korzyści. Nie optymalizuj algorytmu, aby zaoszczędzić kilka cykli tu i tam, gdy nie spowoduje to wymiernego wzrostu wydajności.

Na przykład: możesz poprawić wydajność funkcji, wprowadzając ją, prawdopodobnie oszczędzając garść cykli, ale jednocześnie prawdopodobnie zwiększysz rozmiar pliku wykonywalnego, zwiększając szanse na brak TLB i pamięć podręczną kosztującą tysiące cykli, a nawet operacje stronicowania, które całkowicie zabijają wydajność. Jeśli nie rozumiesz tych rzeczy, Twoja „optymalizacja” może okazać się zła.

Głupia optymalizacja jest bardziej zła niż optymalizacja „przedwczesna”, ale obie są jeszcze lepsze niż przedwczesna nieoptymalizacja.


6

Istnieją dwa problemy z PO: po pierwsze, czas programowania jest wykorzystywany do nieistotnej pracy, którą można wykorzystać do napisania większej liczby funkcji lub naprawienia większej liczby błędów, a po drugie, fałszywego poczucia bezpieczeństwa, że ​​kod działa skutecznie. PO często wiąże się z optymalizacją kodu, który nie będzie wąskim gardłem, a jednocześnie nie zauważa kodu, który to zrobi. Bit „przedwczesny” oznacza, że ​​optymalizacja jest wykonywana przed zidentyfikowaniem problemu za pomocą odpowiednich pomiarów.

Zasadniczo tak, to brzmi jak przedwczesna optymalizacja, ale niekoniecznie musiałbym ją wycofać, chyba że wprowadzi błędy - w końcu został zoptymalizowany teraz (!)


Chcesz powiedzieć „pisz więcej testów” zamiast „pisz więcej funkcji”, prawda? :)
Greg Hewgill

1
więcej funkcji pociąga za sobą więcej testów :)
workmad3

Eee, tak! Właśnie to miałem na myśli ...
harriyott,

2
Kod wprowadza dodatkową złożoność i prawdopodobnie nie będzie powszechnie używany. Utworzenie kopii zapasowej (i podobnych rzeczy) utrzymuje kod w czystości.
Paul de Vrieze

3

Uważam, że to, co Mike Cohn nazywa „pozłacaniem” kodu - tj. Spędzanie czasu na rzeczach, które mogą być fajne, ale nie są konieczne.

Odradzał to.

PS „Pozłacanie” może być swoistą funkcjonalnością. Kiedy patrzysz na kod, przyjmuje on formę niepotrzebnej optymalizacji, „przyszłościowych” klas itp.


2
Myślę, że „pozłacanie” różni się od optymalizacji. Optymalizacje zasadniczo polegają na próbie uzyskania jak największej wydajności, podczas gdy „pozłacanie” polega na dodaniu „dzwonków i gwizdków” (wszystkie dodatkowe funkcje), które nie są krytyczne dla produktu, ale wyglądają / są fajne.
Scott Dorman

3

Ponieważ nie ma problemu ze zrozumieniem kodu, ten przypadek można uznać za wyjątek.

Ale ogólnie optymalizacja prowadzi do mniej czytelnego i mniej zrozumiałego kodu i powinna być stosowana tylko w razie potrzeby. Prosty przykład - jeśli wiesz, że musisz posortować tylko kilka elementów - skorzystaj z BubbleSort. Ale jeśli podejrzewasz, że liczba elementów może wzrosnąć, a nie wiesz ile, optymalizacja za pomocą QuickSort (na przykład) nie jest zła, ale musi. I to należy wziąć pod uwagę podczas projektowania programu.


1
Nie zgadzam się Powiedziałbym, że nigdy nie używaj sortowania bąbelkowego. Quicksort stał się standardem defacto i jest dobrze zrozumiały i jest tak samo łatwy do wdrożenia, jak sortowanie bąbelkowe we wszystkich scenariuszach. Najniższy wspólny mianownik nie jest już tak niski;)

1
W przypadku naprawdę niewielkiej liczby elementów rekursja wymagana dla szybkiego sortowania może sprawić, że będzie wolniejsza niż przyzwoita seria bąbelków ... nie wspominając o tym, że
opcja bąbelków

tak, ale to tylko przykład, jak wybrać algorytmy dla różnych potrzeb;)

To prawda, ale jako domyślny sort miałbym szybki. Gdybym myślał, że bąbelki poprawią wydajność, byłaby to optymalizacja, a nie na odwrót. Jako domyślny wybrałem Quicksort, ponieważ jest dobrze zrozumiany i ogólnie lepszy.

2
Moją ideą domyślnego sortowania jest wszystko, co daje mi biblioteka (qsort (), .sort (), (sort ...), cokolwiek).
David Thornley,

3

Przekonałem się, że problem z przedwczesną optymalizacją występuje najczęściej, gdy przepisywanie istniejącego kodu jest szybsze. Widzę, jak może być problemem napisanie zawiłej optymalizacji w pierwszej kolejności, ale przede wszystkim widzę, że przedwczesna optymalizacja podnosi brzydką głowę w naprawianiu tego, co nie jest (znane).

A najgorszym tego przykładem jest sytuacja, w której widzę, jak ktoś ponownie implementuje funkcje ze standardowej biblioteki. To jest główna czerwona flaga. Na przykład widziałem kiedyś, jak ktoś implementuje niestandardowe procedury manipulacji ciągami, ponieważ martwił się, że wbudowane polecenia są zbyt wolne.

Powoduje to, że kod jest trudniejszy do zrozumienia (źle) i powoduje spalenie dużej ilości czasu na pracę, która prawdopodobnie nie jest przydatna (zła).


3

Z innej perspektywy, z mojego doświadczenia wynika, że ​​większość programistów / programistów nie planuje sukcesu, a „prototyp” to prawie zawsze wersja 1.0. Mam doświadczenie z pierwszej ręki z 4 oddzielnymi oryginalnymi produktami, w których elegancki, seksowny i wysoce funkcjonalny interfejs (w zasadzie interfejs użytkownika) zaowocował szerokim przyjęciem użytkowników i entuzjazmem. W każdym z tych produktów problemy z wydajnością zaczęły wkradać się w stosunkowo krótkim czasie (1–2 lata), zwłaszcza gdy duzi, bardziej wymagający klienci zaczęli wprowadzać ten produkt. Bardzo szybko wydajność zdominowała listę problemów, chociaż rozwój nowych funkcji zdominował listę priorytetów zarządzania. Klienci byli coraz bardziej sfrustrowani, gdy każde wydanie zawierało nowe funkcje, które brzmiały świetnie, ale były prawie niedostępne z powodu problemów z wydajnością.

Tak więc bardzo fundamentalne wady w projektowaniu i wdrażaniu, które nie były obojętne w „typie prototypu”, stały się poważnymi przeszkodami dla długoterminowego sukcesu produktów (i firm).

Demo klienta może wyglądać i działać świetnie na twoim laptopie dzięki DOM DOM XML, SQL Express i dużej ilości buforowanych danych po stronie klienta. System produkcyjny prawdopodobnie spowoduje awarię, jeśli ci się powiedzie.

W 1976 r. Wciąż debatowaliśmy nad optymalnymi sposobami obliczania pierwiastka kwadratowego lub sortowania dużej tablicy, a przysłowie Dona Knutha skierowane było na błąd polegający na skupieniu się na optymalizacji tego rodzaju rutynowych działań na wczesnym etapie procesu projektowania, a nie na rozwiązaniu problemu a następnie optymalizowanie zlokalizowanych regionów kodu.

Kiedy ktoś powtarza powiedzenie jako wymówkę, by nie pisać wydajnego kodu (C ++, VB, T-SQL lub w inny sposób), albo nie projektować właściwie magazynu danych, albo nie brać pod uwagę architektury sieciowej, wtedy IMO po prostu demonstruje bardzo płytkie zrozumienie prawdziwej natury naszej pracy. Promień


1
Haha, lub kiedy demo z trzema użytkownikami stanie się wersją 1.0 z tysiącem.
Olof Forshell,

1

Przypuszczam, że zależy to od tego, jak zdefiniujesz „przedwczesny”. Szybkie działanie funkcji niskiego poziomu podczas pisania nie jest z natury złe. Myślę, że to nieporozumienie z cytatem. Czasami myślę, że ten cytat może przydać się w przypadku pewnych kwalifikacji. Chciałbym jednak powtórzyć komentarze m_pGladiatora dotyczące czytelności.


1

Odpowiedź brzmi: to zależy. Będę argumentować, że wydajność jest bardzo ważna w przypadku niektórych rodzajów pracy, takich jak złożone zapytania do bazy danych. W wielu innych przypadkach komputer spędza większość czasu, czekając na dane wejściowe od użytkownika, dlatego optymalizacja większości kodu jest w najlepszym wypadku stratą wysiłku, aw najgorszym przypadku przynosi efekt przeciwny do zamierzonego.

W niektórych przypadkach możesz zaprojektować wydajność lub wydajność (postrzeganą lub rzeczywistą) - wybierając odpowiedni algorytm lub projektując interfejs użytkownika, aby na przykład niektóre kosztowne operacje zachodziły w tle. W wielu przypadkach profilowanie lub inne operacje mające na celu określenie hotspotów przynoszą korzyść 10/90.

Jednym z przykładów tego, co mogę opisać, jest model danych, który kiedyś stworzyłem dla systemu zarządzania sprawami sądowymi, który zawierał około 560 tabel. Zaczęło się znormalizować („pięknie znormalizowana”, jak to ujęli konsultant z pewnej dużej firmy 5) i musieliśmy w niej umieścić tylko cztery elementy zdormalizowanych danych:

  • Jeden zmaterializowany widok do obsługi ekranu wyszukiwania

  • Jedna tabela obsługiwana przez wyzwalacze do obsługi innego ekranu wyszukiwania, którego nie można było wykonać w widoku zmaterializowanym.

  • Jedna zdenormalizowana tabela raportowania (istniała tylko dlatego, że musieliśmy wziąć na siebie niektóre raporty przepustowości, gdy projekt hurtowni danych został zapełniony)

  • Jedna tabela utrzymywana przez wyzwalacz dla interfejsu, który musiał wyszukiwać najnowsze z dość dużej liczby różnych zdarzeń w systemie.

Był to (w tym czasie) największy projekt J2EE w Australii - znacznie ponad 100 lat czasu programisty - i zawierał 4 zdormalizowane elementy w schemacie bazy danych, z których jeden tak naprawdę w ogóle tam nie należał.


1

Przedwczesna optymalizacja nie jest źródłem CAŁEGO zła, to na pewno. Są jednak wady:

  • inwestujesz więcej czasu w rozwój
  • poświęcasz więcej czasu na testowanie
  • poświęcasz więcej czasu na naprawianie błędów, których inaczej nie byłoby

Zamiast przedwczesnej optymalizacji można wykonać wczesne testy widoczności, aby sprawdzić, czy istnieje rzeczywista potrzeba lepszej optymalizacji.


1

Większość osób, które stosują się do „PMO” (czyli częściowego cytatu), twierdzi, że optymalizacje muszą opierać się na pomiarach, a pomiarów nie można wykonać aż do samego końca.

Z moich doświadczeń związanych z opracowywaniem dużych systemów wynika również, że testy wydajności przeprowadzane są na samym końcu, w miarę jak programowanie dobiega końca.

Gdybyśmy zastosowali się do „rad” tych ludzi, wszystkie systemy byłyby niezwykle powolne. Byłyby również drogie, ponieważ ich potrzeby sprzętowe są znacznie większe niż pierwotnie przewidywano.

Od dawna zalecałem przeprowadzanie testów wydajności w regularnych odstępach czasu w procesie programowania: będzie to oznaczać zarówno obecność nowego kodu (tam, gdzie wcześniej go nie było), jak i stan istniejącego kodu.

  • Wydajność nowo zaimplementowanego kodu można porównać z wydajnością istniejącego, podobnego kodu. „Czułość” wydajności nowego kodu zostanie ustalona z czasem.
  • Jeśli istniejący kod nagle oszaleje, rozumiesz, że coś się z nim stało i możesz to zbadać natychmiast, a nie (znacznie) później, gdy wpłynie to na cały system.

Innym pomysłem zwierzaka jest oprogramowanie oprogramowania na poziomie bloku funkcyjnego. Podczas wykonywania system zbiera informacje o czasach wykonania bloków funkcyjnych. Po przeprowadzeniu aktualizacji systemu można określić, które bloki funkcyjne działają tak, jak we wcześniejszej wersji, oraz te, które uległy pogorszeniu. Na ekranie oprogramowania można uzyskać dostęp do danych dotyczących wydajności z menu pomocy.

Sprawdź ten znakomity artykuł na temat tego, co PMO może, ale nie musi oznaczać.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.