Niedawno przeczytałem post na blogu Three Big Lies i trudno mi uzasadnić drugie kłamstwo, które jest cytowane tutaj:
(LIE # 2) KOD MUSI BYĆ ZAPROJEKTOWANY WOKÓŁ MODELU ŚWIATA
Nie ma żadnej wartości w kodzie będącym jakimś modelem lub mapą wyimaginowanego świata. Nie wiem, dlaczego jest tak atrakcyjny dla niektórych programistów, ale jest niezwykle popularny. Jeśli w grze jest rakieta, możesz mieć pewność, że istnieje klasa „Rakieta” (zakładając, że kod to C ++), która zawiera dane dokładnie dla jednej rakiety i wykonuje rakietowe rzeczy. Bez względu na to, jaka transformacja danych jest rzeczywiście wykonywana, ani na układ danych. Lub, jeśli o to chodzi, bez podstawowego zrozumienia, że tam, gdzie jest jedna rzecz, prawdopodobnie jest więcej niż jedna.
Chociaż za tego rodzaju projekty istnieje wiele kar za wydajność, najbardziej znaczące jest to, że nie skaluje się. W ogóle. Sto rakiet kosztuje sto razy więcej niż jedna rakieta. I jest bardzo prawdopodobne, że kosztuje to jeszcze więcej! Nawet nie-programistom nie powinno to mieć żadnego sensu. Ekonomia skali. Jeśli masz coś więcej, powinno stać się tańsze, a nie droższe. Sposobem na to jest odpowiednie zaprojektowanie danych i pogrupowanie rzeczy według podobnych przekształceń.
Oto moje problemy z tym kłamstwem.
Kod ma wartość modelu / mapy wyobrażonego świata, ponieważ modelowanie wyobrażonego świata pomaga (przynajmniej ja, osobiście) wizualizować i organizować kod.
Posiadanie klasy „Rakieta” jest dla mnie idealnie uzasadnionym wyborem na klasę. Być może „rakiety” można podzielić na typy rakiet, takie jak AGM-114 Hellfire itp., Które zawierają siłę nośną, maksymalną prędkość, maksymalny promień skrętu, typ celowania itd., Ale nadal każda wystrzelona rakieta musi mieć pozycję i prędkość.
Oczywiście posiadanie 100 rakiet kosztuje więcej niż 1 rakietę. Jeśli na ekranie jest 100 Rakiet, musi być 100 różnych obliczeń, aby zaktualizować ich pozycję. Drugi akapit brzmi, jakby twierdził, że jeśli jest 100 rakiet, aktualizacja stanu powinna kosztować mniej niż 100 obliczeń?
Mój problem polega na tym, że autor przedstawia „wadliwy” model programowania, ale nie przedstawia sposobu na jego „poprawienie”. Być może podchodzę do analogii z klasą rakiet, ale naprawdę chciałbym zrozumieć powód tego kłamstwa. Jaka jest alternatywa?
źródło
Odpowiedzi:
Po pierwsze, spójrzmy na jakiś kontekst: jest to projektant gry piszący na blogu, którego tematem jest wyliczanie ostatniej spadku wydajności z procesora Cell BE. Innymi słowy: chodzi o programowanie gier konsolowych, a dokładniej programowanie gier konsolowych na PlayStation 3.
Teraz programiści gier to ciekawa gromada, jeszcze bardziej programiści gier konsolowych, a Cell BE to dość dziwny procesor. (Jest powód, dla którego Sony zdecydowało się na bardziej konwencjonalny projekt na PlayStation 4!)
Musimy więc spojrzeć na te stwierdzenia w tym kontekście.
Istnieje również kilka uproszczeń w tym poście na blogu. W szczególności ten kłamstwo nr 2 jest źle przedstawiony.
Twierdziłbym, że wszystko , co abstrahuje od realnego świata, jest w pewnym sensie modelem. A ponieważ oprogramowanie nie jest rzeczywiste, ale wirtualne, zawsze jest abstrakcją, a zatem zawsze modelem. Ale! Model nie musi mieć czystego mapowania 1: 1 na prawdziwy świat. To w końcu sprawia, że jest to model.
W pewnym sensie autor jest w błędzie: oprogramowanie jest modelem. Kropka. W pewnym sensie ma rację: ten model wcale nie musi przypominać prawdziwego świata.
Podam przykład, który już dawno podałem w innych odpowiedziach, (nie) słynny przykład Wprowadzenie do rachunku bankowego OO 101. Oto jak wygląda konto bankowe w prawie każdej klasie OO w historii:
A więc:
balance
jest to dane itransfer
jest operacją .Ale! Oto jak wygląda konto bankowe w prawie każdym oprogramowaniu bankowym:
Tak, teraz
transfer
jest dane ibalance
jest operacja (w lewo zagiąć dziennika transakcji). (Zauważysz również, żeTransactionSlip
jest niezmienna,balance
jest czystą funkcją,TransactionLog
może być jedynie „prawie” niezmienną strukturą danych tylko z dopiskiem… Jestem pewien, że wielu z was zauważyło rażące błędy współbieżności w pierwszej implementacji, które teraz magicznie znikają .)Zauważ, że oba są modelami. Oba są równie ważne. Oba są poprawne. Oba modele modelują to samo. A jednak są one dokładnie dualne : wszystko, co jest danymi w jednym modelu, jest operacją w drugim modelu, a wszystko, co jest operacją w jednym modelu, to dane w drugim modelu.
Zatem pytanie nie dotyczy tego , czy modelujesz „prawdziwy świat” w swoim kodzie, ale jak go modelujesz.
Jak się okazuje, drugi model jest tak naprawdę działaniem bankowości w prawdziwym świecie. Jak już wspomniałem powyżej, ten drugi model jest w większości niezmienny i czysty oraz odporny na błędy współbieżności, co w rzeczywistości jest bardzo ważne, jeśli weźmie się pod uwagę, że nie było tak dawno temu, gdzie
TransactionSlip
były faktyczne kartki papieru, które zostały wysłane konno i powóz.Jednak fakt, że ten drugi model faktycznie pasuje zarówno do tego, jak działa bankowość w świecie rzeczywistym, jak i do tego, jak działa oprogramowanie do bankowości w świecie rzeczywistym, nie powoduje, że staje się ona w jakiś sposób bardziej „odpowiednia”. Ponieważ tak naprawdę pierwszy („zły”) model dość dokładnie przybliża sposób, w jaki klienci bankowości postrzegają swój bank. Do nich ,
transfer
to operacja (mają do wypełnienia formularza), abalance
to kawałek danych na dnie ich wyciągu z rachunku.Może więc być prawdą, że w podstawowym kodzie silnika gry wysokowydajnej strzelanki PS3 nie będzie żadnego
Rocket
typu, ale nadal będzie istniało pewne modelowanie świata, nawet jeśli model wygląda dziwnie dla kogoś, kto nie jest ekspertem w dziedzinie programowania silnika fizyki gier konsolowych.źródło
balance
dane i transakcje jako więcej danych, a przelewy jako operacje, ponieważ to właśnie widzi użytkownik, nawet jeśli zaplecze może traktować je inaczej.Nie zgadzam się z każdym „kłamstwem”, które proponuje.
TL; DR Autor tego artykułu starał się być kontrowersyjny, aby uczynić ich artykuł bardziej interesującym, ale tak zwane „kłamstwa” są akceptowane przez twórców oprogramowania z dobrych powodów.
Kłamstwo 1 - Duże O ma znaczenie dla celów skalowania. Nikt nie dba o to, czy mała aplikacja zajmuje więcej czasu, co jest jedyną stałą czasową, ważne, że gdy podwoją rozmiar wejściowy, nie zwielokrotni czasu wykonania przez współczynnik 10.
Kłamstwo 2 - Modelowanie programów po rzeczywistym świecie pozwala programiście spojrzeć na twój kod 3 lata później, aby łatwo zrozumieć, co robi. Kod musi być łatwy do utrzymania, w przeciwnym razie musisz poświęcić wiele godzin, próbując zrozumieć, co program robi. Inna odpowiedź sugeruje, że możesz mieć bardziej ogólne klasy, takie jak
LaunchPad
iMassiveDeviceMover
. Niekoniecznie są to złe klasy, ale nadal będziesz ich potrzebowaćRocket
. Skąd ktokolwiek powinien wiedzieć, coMassiveDeviceMover
robi lub co się porusza? Czy porusza się po górach, statkach kosmicznych czy planetach? Zasadniczo oznacza to, że dodawanie takich klas jakMassiveDeviceMover
czyni program mniej wydajnym (ale być może znacznie bardziej czytelnym i zrozumiałym).Dodatkowo koszt czasu programisty już dawno zaczął przewyższać koszt sprzętu. To okropny pomysł, aby zacząć od optymalizacji z przodu swoich myśli. Programujesz go w łatwy i zrozumiały sposób, a następnie poprawiasz program po ustaleniu, które części programów zajmują dużo czasu. Nie zapomnij: 80% czasu wykonania jest wykorzystywane przez 20% programu.
Kłamstwo 3 - Kod jest niezwykle ważny. Dobrze napisany (i modułowy) kod pozwala na ponowne wykorzystanie (oszczędzając niezliczoną liczbę roboczogodzin). Pozwala także na przesiewanie i rozpoznawanie złych danych, aby można było je obsłużyć. Dane są cudowne, ale bez kodu nie byłoby możliwe ich przeanalizowanie i uzyskanie przydatnych informacji.
źródło
W systemie e-commerce nie zajmujesz się „rakietami” na poziomie klasowym, lecz „produktami”. To zależy od tego, co próbujesz osiągnąć i od pożądanego poziomu abstrakcji.
W grze można argumentować, że rakiety są tylko jednym z wielu rodzajów „ruchomych obiektów”. Dotyczy to tej samej fizyki, co wszystkich innych ruchomych obiektów. Przynajmniej „rakieta” odziedziczy po jakiejś bardziej ogólnej klasie bazowej „ruchomych obiektów”.
W każdym razie autor cytowanego przez ciebie fragmentu nieco zawyżał swoją sprawę. Rakiety mogą nadal mieć unikalne cechy, takie jak „pozostała ilość paliwa” i „ciąg”, i nie potrzebujesz stu klas, aby reprezentować to dla stu rakiet, potrzebujesz tylko jednej. Tworzenie obiektów jest dość tanie w większości przyzwoitych języków programowania, więc jeśli chcesz śledzić rzeczy podobne do rakiet, pomysł, że nie powinieneś tworzyć obiektów rakietowych, ponieważ może być zbyt drogi, nie ma większego sensu.
źródło
Problemem w prawdziwym świecie jest cała ta przeklęta fizyka. W prawdziwym świecie dzielimy rzeczy na obiekty fizyczne, ponieważ łatwiej je przemieszczać niż pojedyncze atomy lub gigantyczny stopiony żużel czegoś, co potencjalnie może być rakietą.
Podobnie rzeczywisty świat zapewnia wiele przydatnych funkcji, na których polegamy. Naprawdę łatwo jest zrobić wyjątek od pingwina - „wszystkie ptaki latają, z wyjątkiem…”. I naprawdę łatwo jest nazwać rzeczy rakietami, to znaczy, jeśli nazywam tego pingwina rakietą i zapalam ... to po prostu nie działa.
Tak więc, jak rozdzielamy rzeczy w świecie rzeczywistym, koncepcyjnie działa pod tymi ograniczeniami. Kiedy robimy rzeczy w kodzie, powinniśmy rozdzielić rzeczy, aby działały dobrze w tych ograniczeniach, które są zdecydowanie różne.
Pomyśl o sieciach. Nie modelujemy portów, przewodów i routerów w kodzie. Zamiast tego dzielimy komunikację sieciową na połączenia i protokoły. Robimy to, ponieważ jest to użyteczna abstrakcja niezależnie od implementacji w prawdziwym świecie. I nakłada użyteczne ograniczenia (np .: nie można się komunikować, dopóki połączenie nie zostanie otwarte), które mają znaczenie tylko w kodzie .
Tak, czasami modelowanie kodu po rzeczywistym świecie działa, ale to zbieg okoliczności . Kiedy ludzie mówią o OOP, obiekty nie są obiektami ze świata rzeczywistego. To, że szkoły i samouczki mówią inaczej, jest tragiczną dekadą.
źródło
Rocket
w kodzie tego faceta nie ma żadnego typu, jestem gotów się założyć, że istnieje jednak jakiś model…Alternatywą jest modelowanie rzeczy, o które dbają twoje programy. Nawet jeśli twój program zajmuje się rakietami, być może nie będziesz potrzebować bytu o nazwie
Rocket
. Na przykład możesz miećLaunchPad
encję orazLaunchSchedule
encję iMassiveDeviceMover
encję. Fakt, że wszystko to pomaga w wystrzeliwaniu rakiet, nie oznacza, że sam radzisz sobie z rakietami.źródło
To jest prawdziwy problem, ale dam ci moją opinię jako programisty, może to pomoże.
Po pierwsze, nie nazwałbym tego kłamstwem, jako powszechne nieporozumienia. Nazywanie tego kłamstwem to tylko szum.
Jeden On ma rację pod pewnymi względami. Nie zamierzam poświęcać na to dużo czasu, ponieważ nie jest to częścią pytania. Ale w gruncie rzeczy ma rację. Mógłbym to powtórzyć jako „To, co działa w laboratorium, może nie działać w prawdziwym życiu”. Zbyt wiele razy programiści trzymają się projektu, który działa w „laboratorium”, ale zawodzi w rzeczywistych aplikacjach.
Three Brzmi dla mnie trochę jak mydło, ale w gruncie rzeczy znowu ma rację. Ale można to napisać od nowa: „pisz kod wokół swoich potrzeb, nie próbuj dopasowywać potrzeb do swojego kodu”.
Dwa Znowu, tutaj ma rację. Widziałem, jak programiści spędzili tygodnie lub dłużej, rozwijając klasę „rakietową”, kiedy działałaby prosta klasa „pojazdu” lub nawet prostsza, „ruchoma” klasa. Jeśli wszystko, co musisz zrobić, to przesunąć się z lewej strony ekranu na prawą i wydać dźwięk, możesz użyć tej samej klasy co dla samochodów, pociągów, łodzi i much. Argument 100 powinien kosztować mniej niż 1 * 100, wydaje się, że jest to czas poświęcony na rozwój, a nie tyle na koszty obliczeń. Chociaż trzymanie się mniejszej liczby klas ogólnych, że ponowne użycie jest „tańsze”, to wiele konkretnych klas, których nie można ponownie wykorzystać. Można to prawdopodobnie przepisać, ponieważ „klasy ogólne są lepsze niż określone klasy,
Zasadniczo cały artykuł mógłby zostać przepisany, z mniejszą liczbą modnych słów, a w najlepszym razie byłby to tylko akapit. To powiedziawszy, jest to blog poświęcony wąskiemu obszarowi programowania. Zrobiłem trochę programowania wbudowanego i mogę się zgodzić z ogólną ideą tych oświadczeń, chociaż wokół nich jest sporo „puchu”, aby nadać się do prezentacji na GDC.
Ostatnia uwaga, artykuł został napisany w 2008 roku (najlepiej, co mogłem powiedzieć). Rzeczy zmieniają się szybko. Stwierdzenia są dziś prawdziwe, ale systemy osadzone są dziś znacznie bardziej powszechne i zmieniają się wzorce programistyczne. Być może nawet w odpowiedzi na ten artykuł / wykład.
źródło
Uważam za interesujące, że leżą one wokół problemów akademickich: platformy, wydajności wykorzystania pamięci i danych. Ale całkowicie ignoruje element ludzki.
Oprogramowanie polega na zaspokajaniu potrzeb ludzi. Zazwyczaj jest to wyrażone ilościowo w kategoriach biznesowych - są klienci, którzy czegoś chcą, i sponsorzy, którzy są gotowi zapłacić, aby tak się stało. Jeśli oprogramowanie jest pisane w taki sposób, aby spełniało potrzeby obu stron równania, to jest to dobre oprogramowanie, jeśli nie, to jest złe.
Jeśli platforma nie jest ważna dla klienta, to platforma nie jest ważna. Jeśli wydajność pamięci nie jest ważna dla klienta, to nie jest ważna. Jeśli dane nie są ważne dla klienta, dane nie są ważne. Jeśli kod działa, ale nie można go odczytać ani zachować, a klient chce szybkich i niezawodnych zmian za przyzwoitą cenę, źle napisany kod jest złą rzeczą. Jeśli kod działa, ale nie można go odczytać ani zachować, a klient nie dba o to lub jest gotów zapłacić za drogie programy refaktorskie, to źle napisany kod jest dobrą rzeczą.
Wielkim kłamstwem jest to, że wszystko oprócz ludzkiego elementu ma znaczenie. Dlaczego dane są ważne? Ponieważ jest jakiś klient lub interesariusz, który tego potrzebuje. To jest „wielka prawda”.
źródło
IMHO Jeśli kod jest „zaprojektowany wokół modelu świata”, łatwiej jest go zrozumieć zarówno dla projektantów i programistów, jak i dla opiekunów. Ale myślę, że to nie tylko ja, a nie tylko oprogramowanie. Z Wikipedii: Modelowanie naukowe to działalność naukowa, której celem jest ułatwienie zrozumienia, zdefiniowania, kwantyfikacji, wizualizacji lub symulacji określonej części lub cechy świata poprzez odniesienie do istniejącej i zwykle powszechnie akceptowanej wiedzy
źródło