Najbardziej żenujące błędy w mojej karierze programistycznej (jak dotąd)

Najbardziej żenujące błędy w mojej karierze programistycznej (jak dotąd)
Jak to mówią, jeśli nie wstydzisz się swojego starego kodu, to nie rozwijasz się jako programista – i ja się z tą opinią zgadzam. Zacząłem programować dla zabawy ponad 40 lat temu, a zawodowo 30 lat temu, więc popełniam mnóstwo błędów. bardzo. Jako profesor informatyki uczę moich studentów, aby uczyli się na błędach – ich, moich i innych. Myślę, że czas porozmawiać o swoich błędach, aby nie stracić skromności. Mam nadzieję, że komuś się przydadzą.

Trzecie miejsce – kompilator Microsoft C

Moja nauczycielka uważała, że ​​Romea i Julii nie można uznać za tragedię, bo bohaterowie nie mają tragicznej winy – po prostu zachowują się głupio, jak przystało nastolatkom. Wtedy się z nim nie zgadzałem, ale teraz widzę w jego opinii ziarno racjonalności, szczególnie w odniesieniu do programowania.

Kiedy skończyłem drugi rok na MIT, byłem młody i niedoświadczony zarówno pod względem życiowym, jak i programistycznym. Latem odbyłem staż w Microsoft, w zespole kompilatorów C. Na początku zajmowałem się rutynowymi czynnościami, takimi jak obsługa profilowania, a potem powierzono mi pracę nad najfajniejszą (tak myślałem) częścią kompilatora – optymalizacją backendu. W szczególności musiałem ulepszyć kod x86 dla wyciągów gałęzi.

Zdeterminowany, aby napisać optymalny kod maszynowy dla każdego możliwego przypadku, rzuciłem się do basenu na oślep. Jeśli gęstość dystrybucji wartości była duża, wprowadzałem je tabela przejściowa. Jeśli mieli wspólny dzielnik, użyłem go, aby zawęzić tabelę (ale tylko wtedy, gdy dzielenie można było wykonać za pomocą przesunięcie bitowe). Gdy wszystkie wartości były potęgami dwójki, przeprowadziłem kolejną optymalizację. Jeśli zbiór wartości nie spełniał moich warunków, dzieliłem go na kilka możliwych do optymalizacji przypadków i korzystałem z już zoptymalizowanego kodu.

To był koszmar. Wiele lat później powiedziano mi, że programista, który odziedziczył mój kod, nienawidzi mnie.

Najbardziej żenujące błędy w mojej karierze programistycznej (jak dotąd)

Nauczona lekcja

Jak piszą David Patterson i John Hennessy w książce Computer Architecture and Computer Systems Design, jedną z głównych zasad architektury i projektowania jest zapewnienie, aby wszystko działało tak szybko, jak to możliwe.

Przyspieszenie typowych przypadków poprawi wydajność skuteczniej niż optymalizacja rzadkich przypadków. Jak na ironię, typowe przypadki są często prostsze niż rzadkie. Ta logiczna rada zakłada, że ​​wiesz, który przypadek jest uważany za powszechny – a jest to możliwe jedynie poprzez proces dokładnych testów i pomiarów.

Na swoją obronę próbowałem dowiedzieć się, jak w praktyce wyglądają zestawienia oddziałów (np. ile jest oddziałów i jak rozmieszczone są stałe), ale w 1988 r. taka informacja nie była dostępna. Jednakże nie powinienem był dodawać specjalnych przypadków, gdy bieżący kompilator nie był w stanie wygenerować optymalnego kodu dla sztucznego przykładu, który wymyśliłem.

Musiałem zadzwonić do doświadczonego programisty i wspólnie z nim przemyśleć, jakie były najczęstsze przypadki i zająć się nimi konkretnie. Napisałbym mniej kodu, ale to dobrze. Jak napisał założyciel Stack Overflow, Jeff Atwood, najgorszym wrogiem programisty jest on sam:

Wiem, że masz jak najlepsze intencje, podobnie jak my wszyscy. Tworzymy programy i uwielbiamy pisać kod. Tak jesteśmy stworzeni. Uważamy, że każdy problem można rozwiązać za pomocą taśmy klejącej, domowej roboty kuli i szczypty kodu. Choć programistom trudno to przyznać, najlepszy kod to taki, który nie istnieje. Każda nowa linia wymaga debugowania i wsparcia, należy to zrozumieć. Dodając nowy kod należy to robić z niechęcią i obrzydzeniem, gdyż wszystkie inne możliwości zostały wyczerpane. Wielu programistów pisze za dużo kodu, co czyni go naszym wrogiem.

Gdybym napisał prostszy kod, który obejmowałby typowe przypadki, aktualizacja w razie potrzeby byłaby znacznie łatwiejsza. Zostawiłem po sobie bałagan, z którym nikt nie chciał się uporać.

Najbardziej żenujące błędy w mojej karierze programistycznej (jak dotąd)

Drugie miejsce: reklama w sieciach społecznościowych

Kiedy pracowałem w Google nad reklamą w mediach społecznościowych (pamiętasz Myspace?), napisałem coś takiego w C++:

for (int i = 0; i < user->interests->length(); i++) {
  for (int j = 0; j < user->interests(i)->keywords.length(); j++) {
      keywords->add(user->interests(i)->keywords(i)) {
  }
}

Programiści mogą natychmiast zobaczyć błąd: ostatnim argumentem powinno być j, a nie i. Testy jednostkowe nie wykazały błędu, podobnie jak mój recenzent. Uruchomienie zostało przeprowadzone i pewnej nocy mój kod trafił na serwer i spowodował awarię wszystkich komputerów w centrum danych.

Nic złego się nie stało. Nikomu nic się nie zepsuło, bo przed globalną premierą kod był testowany w jednym centrum danych. Chyba że inżynierowie SRE przestali na jakiś czas grać w bilard i trochę się wycofali. Następnego ranka otrzymałem e-mail ze zrzutem awaryjnym, poprawiłem kod i dodałem testy jednostkowe, które wykryły błąd. Ponieważ postępowałem zgodnie z protokołem – w przeciwnym razie mój kod po prostu by się nie uruchomił – nie było innych problemów.

Najbardziej żenujące błędy w mojej karierze programistycznej (jak dotąd)

Nauczona lekcja

Wielu jest przekonanych, że tak poważny błąd z pewnością będzie kosztować zwolnienie sprawcy, ale tak nie jest: po pierwsze, wszyscy programiści popełniają błędy, a po drugie, rzadko popełniają ten sam błąd dwa razy.

Tak naprawdę mam znajomego programistę, który był genialnym inżynierem i został zwolniony za popełnienie jednego błędu. Następnie został zatrudniony w Google (i wkrótce awansował) - szczerze mówił o błędzie, który popełnił w wywiadzie i nie uznano go za fatalny.

Oto co powiedzieć o Thomasie Watsonie, legendarnym szefie IBM:

Ogłoszono zamówienie rządowe o wartości około miliona dolarów. IBM Corporation – a raczej osobiście Thomas Watson senior – naprawdę chciał to zdobyć. Niestety przedstawiciel handlowy nie był w stanie tego zrobić i IBM przegrał przetarg. Następnego dnia pracownik ten przyszedł do biura pana Watsona i położył kopertę na jego biurku. Pan Watson nawet nie zadał sobie trudu, żeby na to spojrzeć – czekał na pracownika i wiedział, że to rezygnacja.

Watson zapytał, co poszło nie tak.

Przedstawiciel handlowy szczegółowo opowiedział o przebiegu przetargu. Wymienił popełnione błędy, których można było uniknąć. Na koniec powiedział: „Panie Watson, dziękuję za umożliwienie mi wyjaśnień. Wiem, jak bardzo potrzebowaliśmy tego zamówienia. Wiem, jak ważny był” i przygotowałem się do wyjścia.

Watson podszedł do niego w drzwiach, spojrzał mu w oczy i zwrócił kopertę ze słowami: „Jak mogę cię wypuścić? Właśnie zainwestowałem milion dolarów w twoją edukację.

Mam koszulkę z napisem: „Jeśli naprawdę uczysz się na błędach, to już jestem mistrzem”. Tak naprawdę, jeśli chodzi o błędy, jestem doktorem nauk.

Pierwsze miejsce: App Inventor API

Naprawdę straszne błędy dotykają ogromną liczbę użytkowników, stają się powszechnie znane, ich poprawianie zajmuje dużo czasu i są popełniane przez tych, którzy nie mogli ich popełnić. Mój największy błąd spełnia wszystkie te kryteria.

Im gorzej tym lepiej

czytam esej Richarda Gabriela O tym podejściu opowiadałem już w latach dziewięćdziesiątych jako student i tak mi się ono podoba, że ​​pytam o to moich studentów. Jeśli nie pamiętasz tego dobrze, odśwież pamięć, jest mała. W tym eseju pod wieloma względami, w tym w prostocie, kontrastuje chęć „zrobienia tego dobrze” z podejściem „gorsze jest lepsze”.

Jak powinno być: projekt powinien być prosty w implementacji i interfejsie. Prostota interfejsu jest ważniejsza niż prostota implementacji.

Im gorzej, tym lepiej: projekt powinien być prosty w implementacji i interfejsie. Prostota wdrożenia jest ważniejsza niż prostota interfejsu.

Zapomnijmy o tym na chwilę. Niestety, przez wiele lat o tym zapomniałem.

Wynalazca aplikacji

Pracując w Google, byłem częścią zespołu Wynalazca aplikacji, internetowe środowisko programistyczne typu „przeciągnij i upuść” dla początkujących programistów Androida. Był rok 2009 i spieszyliśmy się z wydaniem wersji alfa na czas, aby latem móc przeprowadzić kursy mistrzowskie dla nauczycieli, którzy jesienią mogliby korzystać ze środowiska podczas nauczania. Zgłosiłem się na ochotnika do wdrażania spriteów, tęskniąc za tym, jak pisałem gry na TI-99/4. Dla tych, którzy nie wiedzą, duszek to dwuwymiarowy obiekt graficzny, który może się poruszać i wchodzić w interakcję z innymi elementami oprogramowania. Przykładami duszków są statki kosmiczne, asteroidy, kulki i rakiety.

Zaimplementowaliśmy zorientowany obiektowo App Inventor w Javie, więc jest tam tylko kilka obiektów. Ponieważ kulki i duszki zachowują się bardzo podobnie, stworzyłem abstrakcyjną klasę duszków z właściwościami (polami) X, Y, Prędkość (prędkość) i Kierunek (kierunek). Mieli te same metody wykrywania kolizji, odbicia od krawędzi ekranu itp.

Główną różnicą pomiędzy kulką a duszkiem jest to, co dokładnie jest rysowane – wypełnione koło czy raster. Ponieważ najpierw zaimplementowałem duszki, logiczne było określenie współrzędnych x i y lewego górnego rogu miejsca, w którym znajdował się obraz.

Najbardziej żenujące błędy w mojej karierze programistycznej (jak dotąd)
Kiedy duszki zaczęły działać, zdecydowałem, że mogę zaimplementować obiekty kulkowe przy użyciu bardzo małej ilości kodu. Jedynym problemem było to, że wybrałem najprostszą trasę (z punktu widzenia realizatora), wskazując współrzędne x i y lewego górnego rogu konturu otaczającego kulę.

Najbardziej żenujące błędy w mojej karierze programistycznej (jak dotąd)
W rzeczywistości konieczne było wskazanie współrzędnych x i y środka okręgu, jak naucza się w każdym podręczniku matematyki i każdym innym źródle wspominającym o okręgach.

Najbardziej żenujące błędy w mojej karierze programistycznej (jak dotąd)
W przeciwieństwie do moich poprzednich błędów, ten dotknął nie tylko moich kolegów, ale także miliony użytkowników App Inventor. Wielu z nich to dzieci lub osoby, które dopiero zaczynały programować. Pracując nad każdą aplikacją, w której występowała piłka, musieli wykonywać wiele niepotrzebnych kroków. Jeśli pamiętam swoje inne błędy ze śmiechem, to ten do dziś mnie poci.

W końcu załatałem ten błąd dopiero niedawno, dziesięć lat później. „Połatane”, a nie „naprawione”, bo jak mówi Joshua Bloch, interfejsy API są wieczne. Nie mogąc dokonać zmian, które miałyby wpływ na istniejące programy, dodaliśmy właściwość OriginAtCenter z wartością false w starych programach i true we wszystkich przyszłych. Użytkownicy mogą zadać logiczne pytanie: kto w ogóle pomyślał o umieszczeniu punktu początkowego w innym miejscu niż centrum. Do kogo? Do jednego programisty, który dziesięć lat temu był zbyt leniwy, aby stworzyć normalne API.

Zdobyta wiedza

Pracując nad API (co niemal każdy programista ma czasem do czynienia) warto kierować się najlepszymi radami zawartymi w filmie Joshuy Blocha „Jak stworzyć dobre API i dlaczego jest to takie ważne"Or na tej krótkiej liście:

  • API może przynieść zarówno wielkie korzyści, jak i wielkie szkody.. Dobre API tworzy stałych klientów. Zły staje się Twoim wiecznym koszmarem.
  • Publiczne interfejsy API, takie jak diamenty, działają wiecznie. Daj z siebie wszystko: nigdy nie będzie kolejnej szansy, aby zrobić wszystko dobrze.
  • Zarysy API powinny być krótkie — jedna strona z podpisami i opisami klas i metod, zajmująca nie więcej niż linię. Umożliwi to łatwą restrukturyzację API, jeśli za pierwszym razem nie wyjdzie idealnie.
  • Opisz przypadki użyciaprzed wdrożeniem API lub nawet pracą nad jego specyfikacją. W ten sposób unikniesz implementowania i określania całkowicie niefunkcjonalnego API.

Gdybym napisał choćby krótkie streszczenie sztucznym pismem, najprawdopodobniej zidentyfikowałbym błąd i poprawił go. Jeśli nie, to na pewno zrobiłby to któryś z moich kolegów. Każda decyzja, która ma dalekosiężne konsekwencje, wymaga przemyślenia przynajmniej przez jeden dzień (nie dotyczy to tylko programowania).

Tytuł eseju Richarda Gabriela „Gorzej jest lepiej” odnosi się do korzyści wynikającej z bycia pierwszym na rynku – nawet z niedoskonałym produktem – podczas gdy ktoś inny spędza wieczność w pogoni za idealnym. Zastanawiając się nad kodem sprite'a, zdaję sobie sprawę, że nie musiałem nawet pisać więcej kodu, aby zrobić to dobrze. Cokolwiek by ktoś nie powiedział, byłem w ogromnym błędzie.

wniosek

Programiści popełniają błędy każdego dnia, niezależnie od tego, czy piszą błędny kod, czy nie chcą spróbować czegoś, co poprawi ich umiejętności i produktywność. Oczywiście można być programistą nie popełniając tak poważnych błędów jak ja. Ale nie da się zostać dobrym programistą bez rozpoznawania swoich błędów i uczenia się na nich.

Ciągle spotykam studentów, którzy mają wrażenie, że popełniają za dużo błędów i przez to nie nadają się do programowania. Wiem, jak powszechny jest syndrom oszusta w IT. Mam nadzieję, że wyciągniecie wnioski z lekcji, które wymieniłem – ale pamiętajcie o najważniejszej: każdy z nas popełnia błędy – krępujące, śmieszne, okropne. Będę zaskoczony i zdenerwowany, jeśli w przyszłości nie będę miał wystarczającej ilości materiału, aby kontynuować artykuł.

Źródło: www.habr.com

Dodaj komentarz