Copyright 2002, 2003 by Robert L. Read. Udzielane jest pozwolenie by kopiować, rozpowszechniać i/lub modyfikować niniejszy dokument na warunkach licencji GNU Free Documentation, wersja 1.2 lub dowolnej późniejszej wersji opublikowanej przez Free Software Foundation z zastrzeżeniem jednej niezmiennej części, którą stanowi „Historia" (stan na luty 2003). Brak tekstu na przedniej okładce, jeden tekst na tylnej okładce. „Wersja oryginalna niniejszego dokumentu została napisana przez Roberta L. Reada bez wynagrodzenia i jest dedykowana programistom Hire.com". Kopia licencji jest dołączona w części zatytułowanej „Licencja GNU Free Documentation”.
Dedykacja
Dla programistów Hire.com
Rozdział 1. Wprowadzenie
Bycie dobrym programistą jest trudne i szlachetne. Najtrudniejszą rzeczą w urzeczywistnianiu wspólnej wizji projektu programistycznego jest praca ze współpracownikami i klientami. Pisanie programów komputerowych jest ważne oraz wymaga ogromnej inteligencji i wielkich umiejętności. Ale jest to dziecięca igraszka w porównaniu do pozostałych rzeczy, które dobry programista musi robić, by sprawić, żeby oprogramowanie okazało się sukcesem zarówno dla klientów jak i dla niezliczonych kolegów, za których jest częściowo odpowiedzialny. W niniejszym eseju próbuję podsumować tak zwięźle, jak to tylko możliwe, te kwestie, które chciałbym, żeby ktoś wyjaśnił mi kiedy miałem dwadzieścia jeden lat.
Opisuję bardzo subiektywne odczucia, a zatem niniejszy esej siłą rzeczy musi być osobisty i nieco stronniczy. Ograniczam się do problemów, z którymi programista prawdopodobnie będzie musiał się borykać w swojej pracy. Wiele z tych problemów i ich rozwiązań ma na tyle uniwersalny charakter, że prawdopodobnie będę brzmiał jak kaznodzieja. Mam nadzieję, że mimo tego esej ten okaże się użyteczny.
Programowanie jest wykładane na kursach. Znakomite książki: Pragmatyczny programista. Od czeladnika do mistrza [Prag99], Kod doskonały. Jak tworzyć oprogramowanie pozbawione błędów [CodeC93], Rapid Development [RDev96] oraz Extreme Programming Explained [XP99] uczą programowania komputerowego i poruszają co ważniejsze kwestie dotyczące bycia programistą. Przed tym artykułem lub w trakcie jego lektury warto zapoznać się z esejami Paula Grahama [strona Paula Grahama] i Erica Raymonda [Hacker]. Ten esej różni się od wymienionych znakomitych dzieł tym, że, podkreślam w nim problemy natury społecznej i obszernie opisuję wszystkie moim zdaniem niezbędne umiejętności każdego programisty.
W niniejszym eseju określenie szef odnosi się do osoby, która zleca projekty do wykonania. Używam słów przedsiębiorstwo, firma i grono jako synonimów, z tym wyjątkiem, że przedsiębiorstwo kojarzy się z zarabianiem pieniędzy, firma ze współczesnym miejscem pracy, a grono to najogólniej ludzie z którymi łączy cię lojalność.
Witaj w naszym gronie.
Rozdział 2. Początkujący
Osobiste umiejętności
Naucz się debugować
Debugowanie stanowi kamień węgielny bycia programistą. Podstawowym znaczeniem czasownika debugować jest usuwać błędy, ale bardziej istotne jest znaczenie badać program podczas wykonywania. Programista, który nie potrafi efektywnie debugować jest ślepy.
Idealiści myślący że projektowanie, analiza, teoria złożoności lub Bóg wie co jeszcze, są rzeczami o znaczeniu bardziej zasadniczym, nie są czynnymi programistami. Czynny programista nie żyje w świecie idealnym. Nawet jeśli ty jesteś doskonały, zewsząd otacza cię kod napisany przez wiodące firmy programistyczne, organizacje takie jak GNU i twoich kolegów. Musisz go używać, mimo że w większości jest niedoskonały i niedostatecznie udokumentowany. Bez umiejętności wglądu w działanie tego kodu najdrobniejsze potknięcie może cię zawrócić z obranej ścieżki na dobre. Wgląd taki często można dostrzec poprzez eksperymenty, czyli debugowanie.
Istotą debugowania jest uruchamianie programów, a nie programy same w sobie. Jeśli kupujesz coś u wiodącego dostawcy oprogramowania, zwykle nie możesz zobaczyć programu. Ale wciąż będą się pojawiać momenty, kiedy kod nie zgadza się z dokumentacją (zawieszenie twojego komputera to powszechny i spektakularny przykład) lub gdy na dany temat dokumentacja milczy. Jeszcze częściej powodujesz błąd, badasz kod, który napisałeś i nie masz pojęcia w jaki sposób do tego błędu dochodzi. Nieuchronnie oznacza to, że przyjąłeś jakieś fałszywe założenia lub nie przewidziałeś jakiegoś warunku. Czasem magiczna sztuczka polegająca na przypatrywaniu się kodowi źródłowemu działa. Jeśli nie, musisz debugować.
By uzyskać wgląd w działanie programu, musisz być w stanie wykonać kod i obserwować to, co jest w nim szczególne. Czasem jest to widoczne, jak w przypadku gdy zostaje to wyświetlone na ekranie, lub gdy jest to opóźnienie pomiędzy dwoma zdarzeniami. W wielu przypadkach w grę wchodzą rzeczy, które z założenia nie są widoczne, jak np. stan niektórych zmiennych wewnątrz kodu, które linie kodu są właściwie wykonywane lub też czy w skomplikowanej strukturze danych spełnione są warunki asercji. Te ukryte zdarzenia muszą zostać ujawnione.
Najczęściej stosowane sposoby zaglądania do „wnętrzności” wykonywanego programu to:
- używanie narzędzi do debugowania.
- stosowanie instrukcji drukujących dane — dokonywanie tymczasowych modyfikacji programu, zazwyczaj polegających na dodaniu kodu wyświetlającego informacje.
- zapisywanie w dzienniku — tworzenie stałego mechanizmu wglądu w wykonanie programu w formie dziennika.
Narzędzia debugowania są cudowne, gdy są stabilne i dostępne, ale wyświetlanie i zapisywanie w dzienniku są nawet ważniejsze. Narzędzia debugowania często nie nadążają za rozwojem języka, więc w danym momencie mogą nie być dostępne. Ponad to, ponieważ narzędzie debugowania może subtelnie zmieniać sposób wykonywania programu, nie zawsze jest to praktyczne. Wreszcie, są pewne rodzaje debugowania, takie jak sprawdzanie asercji względem dużej struktury danych, które wymaga pisania kodu i zmiany wykonywania programu. Dobrze jest wiedzieć jak używać narzędzi debugowania kiedy są stabilne, ale decydujące jest to, by być w stanie wykorzystać dwie pozostałe metody.
Niektórzy początkujący programiści obawiają się debugowania, gdy wymaga to modyfikacji kodu. To zrozumiałe — to trochę jak rozpoznawczy zabieg chirurgiczny. Lecz musisz nauczyć się „szperać” w kodzie i sprawić, żeby ruszył. Musisz nauczyć się eksperymentować z nim i zrozumieć, że nic, co tymczasowo robisz z nim nie uczyni go gorszym. Jeśli odczuwasz ten strach, poszukaj mentora — tracimy wielu dobrych programistów z powodu tego strachu odczuwanego przez nich na samym początku nauki.
Jak debugować dzieląc przestrzeń problemu
Debugowanie sprawia radość, ponieważ zaczyna się od tejemnicy. Wydaje ci się, że program powinien coś zrobić, a robi coś innego. Nie zawsze jest to tak proste — jakiekolwiek przykłady, które mogę podać będą sztuczne w porównaniu z tym, co czasem dzieje się w praktyce. Debugowanie wymaga kreatywności i oryginalności. Jeśli istnieje jeden klucz do debugowania to jest to technika dziel i zwyciężaj którą stosujemy względem tej tajemnicy.
Załóżmy na przykład, że stworzyłeś program, który powinien wykonać kolejno dziesięć różnych działań. Gdy go uruchamiasz, zawiesza się. Ponieważ nie zaprogramowałeś go by się zawieszał, masz do czynienia z tajemnicą. Kiedy spoglądasz na dane wyjściowe, widzisz że pierwsze siedem działań zostało wykonanych z powodzeniem. Efektu wykonania trech ostatnich nie widać na wyjściu, więc tajemnica jest nieco mniejsza: „Zawiesił się na operacji nr 8, 9 lub 10”.
Czy potrafisz zaprojektować eksperyment by sprawdzić na którym działaniu program się zawiesił? Oczywiście. Możesz użyć debugera lub dodać wyrażenia drukujące dane (lub ich odpowiednik w dowolnym języku, jakiego używasz) po działaniach nr 8 i 9. Gdy uruchamiamy program ponownie, nasza tajemnica jest mniejsza, np. „Zawiesił się na numerze 9". Z doświadczenia wiem, że najłatwiej utrzymać koncentrację na istocie problemu, jeśli cały czas pamięta się, czym dokładnie jest tajemnica. Kiedy kilka osób pracuje nad problemem pod presją, łatwo jest zapomnieć jaka jest najważniejsza tajemnica.
Podstawa techniki dzielenia i zdobywania w debugowaniu jest taka sama, jak przy projektowaniu algorytmu: jeśli będziesz poprawnie dzielić tajemnicę na połowy, nie będziesz musiał robić tego zbyt wiele razy i praca będzie przebiegała sprawnie. Ale gdzie jest środek tajemnicy? Właśnie tutaj przydają się kreatywność i doświadczenie.
Dla początkującego potencjalnym miejscem występowania błędów jest każda linia kodu. Początkujący nie ma jeszcze wyczucia, pozwalającego zobaczyć inne wymiary programu, takie jak przestrzeń wykonywanych linii, struktura danych, zarządzanie pamięcią, komunikacja z obcym kodem, kod stanowiący ryzyko oraz prosty kod. Dla doświadczonego programisty te inne wymiary tworzą niedoskonały, ale bardzo użyteczny model mentalny rzeczy mogących pójść nie tak. Posiadanie takiego modelu pomaga efektywnie znaleźć środek tajemnicy.
Po podzieleniu potencjalnych obszarów błędów na mniejsze części, musisz spróbować zdecydować, w którym z nich tkwi błąd. W prostym przypadku tajemnica sprowadza się do pytania „Która nieznana mi pojedyncza linia sprawia, że program się zawiesza?" i możesz zadać sobie pytanie: „Czy ta nieznana mi linia wykonywana znajduje się przed czy po linii, która moim zdaniem wypada mniej więcej w środku uruchomionego programu?". Zazwyczaj nie będziesz miał tyle szczęścia by wiedzieć, że błąd znajduje się w pojedynczej linii, lub nawet w pojedynczym bloku. Często tajemnica będzie brzmieć: „Albo istnieje wskaźnik w tym grafie, który wskazuje na niewłaściwy węzeł, albo mój algorytm dodający zmienne w tym grafie nie działa”. W tym przypadku może będziesz musiał napisać mały program by sprawdzić czy wskaźniki w tym grafie są poprawne by zdecydować, która część podzielonej na mniejsze części tajemnicy może zostać wyeliminowana.
Jak usunąć błąd
Celowo oddzieliłem czynność badania działania programu od czynności naprawiania błędu. Aczkolwiek, oczywiście, debugowanie oznacza również usuwanie błędu. Byłoby idealnie, gdybyś miał doskonałe rozeznanie w kodzie i doznał olśnienia, kiedy widzisz błąd i wiesz jak go naprawić. Ale jako że w programach często wykorzystywane są niewystarczająco udokumentowane systemy, w które nie ma się wglądu, nie zawsze jest to możliwe. Czasami też kod jest tak skomplikowany, że nie da się go dokładnie poznać.
Naprawiając błąd należy działać tak, aby jak najmniej zmienić w kodzie. Przy okazji można dostrzec inne rzeczy wymagające poprawek, ale nie dokonuj ich w tym samym czasie. Staraj się przestrzegać naukowej metody polegającej na dokonywaniu jednej zmiany na raz. Najlepszym sposobem by to zrobić to móc łatwo odtworzyć błąd, następnie dokonać poprawki, a potem uruchomić ponownie program i obserwować czy błąd wciąż występuje. Oczywiście czasem więcej niż jedna linia wymaga zmian, ale powinieneś wciąż intelektualnie zastosować pojedynczą odrębną zmianę by naprawić błąd.
Czasem zdarza się, że kilka błędów powoduje usterkę, która wygląda jak pojedynczy błąd. Od ciebie zależy jak zdefiniujesz błędy i naprawisz je pojedynczo. Niekiedy nie jest jasne, co program powinien robić lub co jego autor miał na myśli. W tym przypadku musisz wykorzystać swoje doświadczenie i osąd i nadać kodowi swój własny sens. Zdecyduj, co program powinien robić, opatrz to komentarzem lub wyjaśnij to w jakiś inny sposób, a następnie spraw, by kod zgadzał się z obranym przez ciebie sensem. Jest to umiejętność na poziomie średniozaawansowanym i zaawansowanym, która jest czasem trudniejsza niż napisanie swej własnej funkcji, ale świat realny bywa często w nieładzie. Może być też tak, że musisz naprawić system, którego nie możesz napisać od nowa.
Jak debugować używając dziennika
Dziennik to zbiór rekordów zawierających informacje na temat działania systemu. Przykładem użycia tymczasowego dziennika jest zastosowanie instrukcji drukujących dane na ekranie. Początkujący programiści muszą nauczyć się posługiwać się dziennikami, ponieważ mają ograniczoną wiedzę na temat programowania. Architektom systemów dzienniki są potrzebne ze względu na dużą złożoność systemu. Ilość informacji, która jest dostarczana przez dziennik powinna być konfigurowalna, idealnie gdy program jest uruchomiony. Generalnie, dzienniki przedstawiają trzy podstawowe zalety:
- mogą dostarczać użytecznych informacji o błędach, które trudno powtórzyć (np. pojawiających się w środowisku produkcyjnym, których nie można powtórzyć w środowisku testowym).
- mogą dostarczyć statystyk i danych dotyczących wydajności, takich jak czas mijający pomiędzy zapisami.
- gdy są konfigurowalne, dzienniki pozwalają na przechwytywanie ogólnych informacji aby można było debugować nieprzewidziane konkretne problemy bez konieczności modyfikacji i/lub ponownego wdrażania kodu tylko po to, aby rozwiązać te konkretne problemy.
Ilość danych wyjściowych zawartych w dzienniku jest zawsze kompromisem pomiędzy informacją i zwięzłością. Zbyt wiele informacji czyni dziennik drogim i utrudnia znajdowanie istotnych danych. Zbyt mało informacji może nie zawierać danych, które potrzebujesz. Z tego powodu uczynienie danych wyjściowych konfigurowalnymi jest bardzo użyteczne. Zazwyczaj, każdy rekord w dzienniku będzie określał swoją pozycję w kodzie źródłowym, wątek, który go wykonał, o ile to potrzebne, dokładny czas wykonania, oraz, co dość powszechne, dodatkową informację taką jak wartość określonej zmiennej, ilość wolnej pamięci, liczbę obiektów danych itp. Te zapisy w dzienniku są rozsiane w całym kodzie źródłowym, ale w szczególności w miejscach o szczególnej funkcjonalności i wokół kodu niosącego ryzyko. Każdemu zapisowi może zostać przypisany poziom i wyświetli rekord gdy system jest skonfigurowany by wyświetlić właśnie ten poziom. Instrukcje zapisu do dziennika należy tak projektować, by pozwalały rozwiązywać przewidywane problemy. Musisz przewidzieć też potrzebę mierzenia wydajności.
Jeśli masz dziennik trwały, stosowanie instrukcji drukujących dane może zostać wykonane w formie rekordów dziennika, a niektóre zapisy z debugowania będą na stałe dodane do systemu dziennika.
Jak zrozumieć problemy wydajnościowe
Nauczenie się rozumieć wydajność uruchomionego systemu jest nieuniknione z tego samego powodu co nauczenie się czym jest debugowanie. Nawet jeśli kod, który rozumiesz doskonale ma dokładnie taką wydajność, jakiej się spodziewasz, pozostają jeszcze odwołania do innych systemów oprogramowania, nad którymi nie masz kontroli, i do których nie masz wglądu. Jednak w praktyce problemy wydajnościowe są nieco inne i łatwiejsze niż ogólnie debugowanie.
Przyjmijmy, że ty lub twoi klienci uznają system lub podsystem za zbyt powolny. Zanim spróbujesz uczynić go szybszym, musisz zbudować model mentalny dlaczego jest on powolny. By to uczynić, możesz użyć narzędzia do profilowania lub dobrego dziennika by dojść do tego, gdzie czas lub inne zasoby są marnotrawione. Istnieje słynne powiedzenie, że 90 % czasu zużywane jest przez 10 % kodu. Ja podkreśliłbym jeszcze znaczenie kosztów operacji wejścia i wyjścia — często większość czasu jest zużywane właśnie na wykonywanie tych operacji. Znalezienie najbardziej zasobożernych operacji wejścia i wyjścia oraz tych kosztownych 10% kodu jest pierwszym krokiem do stworzenia modelu mentalnego.
Wydajność systemu komputerowego można mierzyć na wielu płaszczyznach i w odniesieniu do wielu różnych rodzajów zasobów. Pomiary należy rozpocząć od czasu zegarowego, czyli łącznego czasu wykonywania obliczeń. Zapisywanie w dzienniku czasu zegarowego jest szczególnie wartościowe ponieważ może poinformować o nieprzewidywalnych okolicznościach, które mogą wystąpić w sytuacjach gdy inne sposoby mierzenia wydajności stają się niepraktyczne. Jednak to nie zawsze daje pełny obraz. Czasem coś co trwa nieco dłużej, ale nie zużywa tak wiele sekund pracy procesora, jest lepsze w środowisku komputerowym, w którym pracujesz. Podobnie pamięć, przepustowość łącza, baza danych oraz dostęp do serwera mogą ostatecznie być znacznie bardziej kosztowne niż sekundy pracy procesora.
Konflikt o współdzielone zsynchronizowane zasoby może powodować zakleszczenie i trwałe zablokowanie programu. Zakleszczenie to niezdolność do kontynuowania pracy z powodu niewłaściwej synchronizacji lub wymagań co do zasobów. Trwałe zablokowanie to brak możliwości kontynuowania pracy spowodowany niewłaściwym zaplanowaniem dostępu do zasobów przez składniki programu. Jeśli może być to w ogóle przewidziane, najlepiej jest mieć sposób pomiaru tego konfliktu już na początku projektu. Nawet jeśli on nie występuje, dobrze jest mieć potwierdzenie.
Jak naprawiać problemy związane z wydajnością
Większość projektów programistycznych można uczynić dzisięcio- do stukrotnie szybszymi przy stosunkowo małym wysiłku w porównaniu z tym, jak działają po opublikowaniu po raz pierwszy. Pod wpływem presji związanej z wprowadzeniem produktu na rynek jest zarówno mądrze jak i efektywnie wybrać rozwiązanie, które wykonuje pracę prosto i szybko, lecz mniej efektywnie niż inne rozwiązania. Jednakże, wydajność stanowi część użyteczności i często musi być ostatecznie rozpatrywana z większą uwagą.
Kluczem do poprawy wydajności bardzo skomplikowanego systemu jest przeprowadzenie dostatecznie dobrze jego analizy tak, by znaleźć wąskie gardła lub miejsca, w których zużywana jest większość zasobów. Optymalizacja funkcji, która odpowiada za zaledwie 1% czasu obliczeń jest pozbawiona sensu. Praktyczna zasada mówi, że powinieneś najpierw dokładnie przemyśleć zanim coś zrobisz, chyba że sądzisz, że uczyni to system lub jego znaczącą część, przynajmniej dwukrotnie szybszym. Zazwyczaj istnieje sposób by to zrobić. Weź pod uwagę test i wysiłek, mający na celu zapewnienie najwyższej jakości, jakiego będzie wymagała ta zmiana. Każda zmiana wiąże się z koniecznością jej sprawdzenia, więc lepiej jest dokonać tylko kilku większych zmian.
Po podwojeniu wydajności systemu musisz przynajmniej przemyśleć ponownie i być może ponownie przeanalizować kod, by znaleźć następne najbardziej kosztowne wąskie gardło i zabrać się do tego by uzyskać kolejną dwukrotną poprawę.
Wąskie gardła to często przypadki analogiczne do liczenia krów poprzez obliczanie liczby nóg i podzielenie wyniku przez cztery zamiast policzenia samych głów. Załóżmy, że popełniłem błąd np. nie dostarczyłem do systemu relacyjnej bazy danych właściwego indeksu do kolumny, którą często wyszukuję, co spowolniło go co najmniej dwudziestokrotnie. Inne przykłady stanowią wykonywanie zbędnych operacji wejścia i wyjścia w pętlach wewnętrznych, pozostawienie dłużej niepotrzebnych wyrażeń debugujących , niepotrzebną alokację pamięci, a w szczególności nieumiejętne wykorzystanie bibliotek i innych podsystemów, które są często słabo udokumentowane pod względem wydajności. Taki sposób usprawnień jest czasem nazywany "nisko zawieszonym owocem" co oznacza, że można łatwo po niego sięgnąć by uzyskać jakąś korzyść.
Lecz co zrobić, gdy owoce te zaczną się wyczerpywać? Cóż, możesz sięgnąć wyżej, lub ściąć drzewo. Możesz w dalszym ciągu dokonywać drobnych poprawek lub możesz poważnie przeprojektować system lub podsystem (stanowi to doskonałą okazję by wykorzystać swoje umiejętności dobrego programisty nie tylko w sensie nowego projektu, ale także przekonania swojego szefa, że jest to dobry pomysł). Jednakże zanim wytoczysz argumenty za zaprojektowaniem od nowa podsystemu, powinieneś zadać sobie pytanie czy twoja propozycja uczyni go od pięcio- do dziesięciokrotnie szybszym.
Jak optymalizować pętle
Czasami wąskie gardło stanowią pętle lub funkcje rekurencyjne o bardzo długim czasie wykonywania. Zanim zaczniesz próbować uczynić pętlę nieco szybszą poświęć chwilę na to, by zastanowić się, czy można ją zupełnie usunąć. Może zadziała inny algorytm? Czy możesz dokonać tych obliczeń obliczając coś innego? Jeśli nie możesz tego ominąć, wówczas możesz optymalizować pętle. To proste: usuwaj jak najwięcej. Ostatecznie będzie to wymagało nie tylko nowatorskiego podejścia, ale także zrozumienia kosztów każdej instrukcji i wyrażenia. Oto kilka sugestii:
- usuń operacje na typach zmiennoprzecinkowych,
- nie alokuj nowych bloków pamięci gdy nie jest to koniecznie,
- stosuj zawijanie stałych,
- przenieś wejście i wyjście do bufora,
- staraj się nie wykonywać dzielenia,
- próbuj nie wykonywać kosztownych rzutowań typów,
- przenieś wskaźnik zamiast ponownie wyliczać indeksy.
Koszt każdej z tych operacji zależy od konkretnego systemu. W niektórych systemach kompilatory i sprzęt wykonają te działania za ciebie. Jasny, efektywny kod jest lepszy niż kod wymagający zrozumienia poszczególnej platformy.
Jak uporać się z kosztem wejścia i wyjścia
Dla wielu problemów procesory są szybkie w porównaniu do kosztów komunikowania się z urządzeniem sprzętowym. Koszt tej komunikacji często skrótowo nazywa się I/O i może obejmować koszt połączenia z siecią lub dyskiem, zapytania do bazy danych, wejściem i wyjściem plików lub innym wykorzystaniem jakiegoś sprzętu odległego względem procesora. Zatem tworzenie szybkiego systemu jest często kwestią poprawy wejścia i wyjścia niż ulepszania kodu zawartego w zwartej pętli lub nawet algorytmu.
Istnieją dwie bardzo podstawowe techniki poprawy wejścia i wyjścia: buforowanie i reprezentacja. Buforowanie polega na unikaniu operacji wejścia i wyjścia (generalnie unikanie wczytywania jakiejś abstrakcyjnej wartości) dzięki zapisywaniu kopii tej wartości lokalnie, więc żadne wejście i wyjście nie jest wykonywane by uzyskać tę wartość. Najważniejsze w buforowaniu jest to, by przejrzyście wskazać, które dane mają charakter nadrzędny, a które są kopiami. Istnieją tylko jedne dane nadrzędne. Koniec, kropka. Buforowanie niesie ze sobą ryzyko, że kopia może nie odzwierciedlać zmian w danych nadrzędnych w sposób natychmiastowy.
Reprezentacja jest metodą sprawiania, aby operacje wejścia i wyjścia były mniej kosztowne poprzez reprezentowanie danych w sposób bardziej efektywny. Często stoi to w sprzeczności z innymi wymaganiami, takimi jak czytelność i przenośność.
Reprezentacja może być polepszona o współczynnik rzędu dwóch lub trzech względem pierwszej implementacji. Techniki osiągania tego obejmują reprezentację binarną zamiast tej czytelnej dla człowieka, przesyłanie słownika symboli razem z danymi tak, że długie symbole nie muszą być zakodowane i , w ekstremalnych przypadkach, rzeczy w rodzaju kodowania Huffmana.
Trzecią techniką, która jest czasem do wykorzystania jest poprawienie lokalności odwołań poprzez zbliżenie obliczeń do samych danych. Np. jeśli wczytujesz jakieś dane z bazy danych i dokonujesz na nich jakichś prostych obliczeń, takich jak dodawanie, spróbuj, żeby serwer bazy danych dokonał tego za ciebie. Zależy to w dużym stopniu od rodzaju systemu z którym pracujesz, ale powinieneś to zbadać.
Jak zarządzać pamięcią
Pamięć jest cennym zasobem i nie możesz sobie pozwolić, żeby jej zabrakło. Możesz ją ignorować przez jakiś czas, ale w końcu będziesz musiał zdecydować jak zarządzać pamięcią.
Przestrzeń, która musi być zachowana poza zasięgiem pojedynczej funkcji jest często nazywana stertą alokowaną. Fragment pamięci jest bezużyteczny, czyli stanowi śmieci, gdy nic się do niego nie odwołuje. W zależności od systemu, którego używasz, będziesz musiał samodzielnie w sposób jawny zwolnić pamięć kiedy będzie zawierała śmieci. Częściej możesz skorzystać z systemu usuwającego śmieci. Odśmiecacz wykrywa śmieci i uwalnia z nich przestrzeń bez jakiegokolwiek działania ze strony programisty. Odśmiecanie jest wspaniałe: zmniejsza błędy i zwiększa zwięzłość kodu oraz jego rzeczowość małym kosztem. Używaj go, gdy tylko możesz.
Ale nawet używając odśmiecania, możesz wypełnić całą pamięć śmieciami. Klasyczną pomyłkę stanowi używanie tablicy mieszającej jako pamięci podręcznej i zapomnienie, by usunąć odniesienia zawarte w tej tabeli. Ponieważ odniesienie pozostaje, obiektu, do którego się ono odnosi, nie da się usunąć, mimo że jest on bezużyteczny. Nazywa się to wyciekiem pamięci. Powinieneś jak najwcześniej szukać i naprawiać wycieki pamięci. Jeśli masz do czynienia z długo działającym systemem, pamięć może nigdy się nie wyczerpać podczas testów, ale zostanie wyczerpana przez użytkownika.
Tworzenie nowych obiektów jest umiarkowanie kosztowne w jakimkolwiek systemie. Jednakże, pamięć przydzielana bezpośrednio w zmiennych lokalnych funkcji jest zazwyczaj mało kosztowna, ponieważ linia postępowania co do uwalniania jej może być bardzo prosta. Powinieneś unikać zbędnego tworzenia obiektów.
Z ważnym przypadkiem mamy do czynienia, gdy możesz definiować górną granicę liczby obiektów, których będziesz potrzebować w jednym momencie. Jeśli obiekty te zajmują taką samą ilość pamięci, możesz być w stanie zaalokować pojedynczy blok pamięci, lub bufor, by je przechowywać. Obiekty, których potrzebujesz, mogą być zaalokowane i zwalniane wewnątrz bufora według stałego wzorca rotacyjnego, który nazywany jest czasem buforem pierścieniowym. Jest to zazwyczaj szybsze niż alokacja na stercie.
Czasem musisz jawnie zwolnić zaalokowaną przestrzeń żeby mogła zostać przydzielona ponownie zamiast używać odśmiecania. Wtedy musisz wykorzystać inteligencję względem każdego fragmentu zaalokowanej pamięci i zaprojektować sposób, w jaki ma ona zostać zwolniona we właściwym czasie. Metoda ta może się zmieniać w zależności od rodzaju obiektu, który stworzyłeś. Musisz się upewnić, że każde wykonanie operacji alokowania pamięci odpowiada ostatecznie stosownej operacji jej zwalniania. Jest to tak trudne, że programiści często po prostu implementują elementarną formę odśmiecania, jak np. zliczanie referencji, by wykonywała to za nich.
Jak uporać się z błędami sporadycznymi
Błąd sporadyczny jest bliskim krewnym błędu przypominającego długiego na piętnaście metrów niewidzialnego skorpiona przybyłego z kosmosu. Ten senny koszmar pojawia się tak rzadko, że ciężko go zaobserwować, ale wystarczająco często, że nie można go ignorować. Nie możesz go zdebugować, ponieważ nie możesz go znaleźć.
Chociaż po ośmiu godzinach zaczniesz w to wątpić, błąd sporadyczny musi podlegać takim samym zasadom logiki jak wszystko inne. Co czyni go tak ciężkim to to, że pojawia się w nieznanych warunkach. Spróbuj zarejestrować okoliczności, w których się pojawia, abyś mógł zgadnąć na czym polega jego zmienność. Warunek może być związany z wartościami danych, jak np. „To zdarza się tylko kiedy wpiszemy Wrocław jako wartość”. Jeśli to nie jest źródłem zmienności, następnym podejrzanym powinna być niewłaściwie zsynchronizowana współbieżność.
Próbuj, próbuj i jeszcze raz próbuj odtworzyć ten błąd w sposób kontrolowany. Jeśli nie możesz go odtworzyć, zastaw na niego pułapkę tworząc system dziennika, nawet specjalnie stworzony dla niego, jeśli to konieczne, tak abyś mógł w nim zapisać to, co wg ciebie jest potrzebne kiedy naprawdę się pojawi. Pogódź się z tym, że jeśli ten błąd pojawia się tylko w produkcji, a nie na twoje życzenie, ten proces może potrwać długo. Wskazówki, które możesz uzyskać z dziennika mogą nie dostarczyć rozwiązania, ale mogą dać dość informacji by usprawnić dziennik. Wdrożenie w produkcję poprawionego systemu dziennika może zabrać dużo czasu. Wówczas musisz czekać, aż błąd pojawi się ponownie, aby uzyskać więcej informacji. Ten cykl może jeszcze potrwać.
Najgłupszy błąd sporadyczny, jaki kiedykolwiek spowodowałem, był w wielowątkowej implementacji funkcyjnego języka programowania dla celów projektu klasowego. Bardzo uważnie upewniłem się co do poprawnej współbieżnej ewaluacji programu funkcyjnego, dobrego wykorzystania wszystkich procesorów (w tym przypadku ośmiu). Po prostu zapomniałem zsynchronizować odśmiecacz. System mógł działać przez długi czas, często kończąc wszystkie zadania, które mu powierzyłem, zanim cokolwiek widocznego poszło nie tak. Ze wstydem przyznaję, że zacząłem mieć wątpliwości co do sprzętu zanim moja pomyłka dotarła do mnie.
W pracy mieliśmy ostatnio błąd sporadyczny i zabrało nam kilka tygodni by go znaleźć. Mamy wielowątkowe serwery aplikacji w Javie na serwerach WWW Apache. By utrzymać szybkie zmienianie stron, wykonujemy wszystkie operacje wejścia i wyjścia w ramach zestawu czterech oddzielnych wątków odmiennych od tych, które odpowiadają za zmienianie stron. Co jakiś czas wątki te blokowały się i przestawały robić cokolwiek użytecznego, na ile nasz dziennik pozwolił nam stwierdzić, godzinami. Ponieważ mieliśmy cztery wątki, to samo w sobie nie było wielkim problemem, chyba że zablokowałyby się wszystkie cztery. Wówczas kolejki opróżnione przez te wątki zapełniłyby szybko całą dostępną pamięć i zawiesiłyby nasz serwer. Zajęło nam około tygodnia, by do tego dojść, ale wciąż nie wiedzieliśmy co było tego powodem, kiedy mogło to nastąpić, a nawet co działo się z wątkami, gdy się blokowały.
To pokazuje pewne ryzyko związane z oprogramowaniem od osób trzecich. Używaliśmy licencjonowanego kodu, który usuwał znaczniki HTML z tekstu. Z powodu jego miejsca pochodzenia nazywaliśmy go pieszczotliwie „francuską striptizerką”. Chociaż mieliśmy kod źródłowy (dzięki opatrzności), nie przestudiowaliśmy go uważnie dopóki nie włączyliśmy dziennika na naszym serwerze i w końcu zdaliśmy sobie sprawę, że wątki e-mail blokowały się przy przetwarzaniu przez „francuską striptizerkę”.
Striptizerka działała dobrze za wyjątkiem niektórych długich i nietypowych rodzajów tekstów. Przy tych tekstach złożoność obliczeniowa kodu była kwadratowa albo i gorzej. To znaczy, że czas przetwarzania był proporcjonalny do kwadratu długości tekstu. Gdyby takie teksty występowały powszechnie, znaleźlibyśmy błąd natychmiast. Gdyby nie pojawiły się w ogóle, nie byłoby problemu. Jak to bywa, minęły tygodnie zanim w końcu zrozumieliśmy i rozwiązaliśmy ten problem.
Jak nabyć umiejętność projektowania
Aby nauczyć się projektować oprogramowanie, przestudiuj działania swoich mentorów będąc fizycznie obecnym, gdy projektują. Następnie zbadaj dobrze napisane oprogramowanie. Później możesz przeczytać książki na temat najnowszych technik projektowania.
Potem musisz robić to sam. Zacznij od małego projektu. Kiedy już skończysz, zastanów się gdzie projekt zawiódł, a gdzie zakończył się powodzeniem oraz w jaki sposób projekt odbiega od początkowej koncepcji. Następnie podejmij się większych projektów, najlepiej wspólnie z innymi osobami. Projektowanie jest kwestią opinii i wymaga lat, by je opanować. Inteligentny programista jest w stanie nauczyć się podstaw zadowalająco w ciągu dwóch miesięcy i rozwijać swą wiedzę od tego momentu.
Naturalne i pomocne jest rozwinięcie swojego własnego stylu, ale pamiętaj, że projektowanie to sztuka a nie nauka. Osoby piszące książki na ten temat mają w tym partykularny interes, by sprawiać wrażenie naukowości. Nie bądź dogmatyczny jeśli chodzi o konkretny styl projektowania.
Jak przeprowadzać eksperymenty
Zmarły nieoceniony Edsger Dijkstra dobitnie wyjaśnił, że informatyka nie jest nauką doświadczalną [ExpCS] i nie opiera się na elektronicznych komputerach. Jak sam to ujął odnosząc się do lat 60.:
…uczyniono wielką szkodę: temat znany jako „informatyka” czyli nauka o komputerach – co, w istocie, brzmi jak określanie chirurgii jako „nauki o nożu” — i zostało mocno zaszczepione w ludzkich umysłach, że informatyka dotyczy wyłącznie maszyn i ich urządzeń peryferyjnych.
Programowanie nie powinno być nauką doświadczalną, ale większość zawodowych programistów nie może sobie pozwolić na luksus angażowania się w to, co Dijkstra miał na myśli mówiąc o informatyce. Musimy pracować w sferze eksperymentowania, tak jak niektórzy, ale nie wszyscy, fizycy. Jeśli za trzydzieści lat programowanie będzie możliwe bez eksperymentowania, będzie to wielkim osiągnięciem informatyki.
Do rodzajów eksperymentów, jakie będziesz musiał wykonywać zaliczają się:
- testowanie systemów za pomocą małych przykładów by zweryfikować czy zgadzają się z dokumentacją lub aby zrozumieć ich reakcję gdy dokumentacji brak;
- testowanie drobnych zmian by sprawdzić, czy rzeczywiście naprawiają błąd;
- mierzenie wydajności systemu w różnych warunkach z powodu niepełnej wiedzy o ich charakterystykach wydajnościowych;
- sprawdzanie integralności danych;
- gromadzenie statystyk, które mogą wskazać rozwiązanie dla ciężkich lub trudnych do odtworzenia błędów.
Nie sądzę, że w niniejszym eseju mogę wyjaśnić projektowanie eksperymentów: będziesz musiał to studiować i praktykować. Aczkolwiek, mogę udzielić dwóch rad.
Po pierwsze, spróbuj jasno określić swoją hipotezę lub asercję, którą próbujesz sprawdzić. Pomaga również zapisanie tej hipotezy, zwłaszcza jeśli jesteś zdezorientowany lub pracujesz z innymi.
Często będziesz musiał zaprojektować całą serię eksperymentów, a każdy z nich oparty będzie na wiedzy zaczerpniętej z poprzedniego eksperymentu. Dlatego powinieneś zaprojektować swoje własne eksperymenty, by zapewnić jak najwięcej możliwych do uzyskania informacji. Niestety, stoi to w sprzeczności z zachowaniem prostoty eksperymentu — będziesz musiał rozwinąć ten osąd poprzez doświadczenie.
Umiejętności pracy w zespole
Dlaczego ocena szacunkowa jest ważna
Aby uzyskać działający system oprogramowania, który będzie aktywnie użytkowany tak szybko jak to tylko możliwe, konieczne jest nie tylko zaplanowania rozwoju, ale także dokumentacji, wdrożenia i marketingu. W projekcie komercyjnym wymagane jest też zaplanowanie sprzedaży i zagadnień finansowych. Bez przewidywalności czasu rozwoju niemożliwe jest zaplanowanie powyższych kwestii efektywnie.
Dobra ocena szacunkowa zapewnia przewidywalność. Managerowie ją uwielbiają i powinni jej dokonywać. Fakt iż nie jest możliwe, zarówno teoretycznie jak i praktycznie, przewidzieć dokładnie jak długo potrwa rozwinięcie oprogramowania jest często spowodowany przez managerów. Prosi się nas cały czas byśmy dokonywali rzeczy niemożliwych i musimy się uczciwie z tym skonfrontować. Jednakże byłoby nieuczciwie nie przyznać, że jest to zadanie niemożliwe i, o ile to konieczne, wyjaśnić dlaczego. Jest ogromna przestrzeń dla błędów w przepływie informacji dotyczących ocen szacunkowych, gdyż ludzie mają zadziwiającą tendencję myśleć życzeniowo, tak że zdanie:
Oceniam, że jeśli w pełni rozumiem problem, jest w 50 % prawdopodobne, że skończymy w ciągu pięciu tygodni (o ile nikt w tym czasie nie będzie nam przeszkadzał)
tak naprawdę oznacza:
Obiecuję, że zrobimy to wszystko w ciągu pięciu tygodni”.
Ta dość powszechna interpretacja problemu wymaga, abyś przedyskutował co znaczy ta ocena ze swoim szefem lub klientem tak, jakbyś miał do czynienia z osobą niezbyt mądrą. Przedstaw ponownie swoje założenia niezależnie od tego, jak oczywiste mogą ci się wydawać.
Jak oszacować czas programowania
Ocena szacunkowa wymaga praktyki. Wymaga też pracy. Wymaga tyle pracy, że może się okazać dobrym pomysłem oszacować czas, jaki trzeba będzie poświęcić, aby dokonać oszacowania, zwłaszcza jeśli zostałeś poproszony o oszacowanie czegoś naprawdę dużego.
A kiedy zostałeś poproszony by zapewnić oszacowanie czegoś dużego, najuczciwiej będzie sprawę przeciągać. Większość inżynierów podchodzi entuzjastycznie i bardzo się starają zadowolić innych, a przeciąganie sprawy z pewnością nie zadowoli tych, którzy przeciąganie sprawy dotyczy. Ale natychmiastowe oszacowanie prawdopodobnie nie będzie ani dokładne, ani uczciwe.
Kiedy już sprawę przeciągasz, możliwe że warto rozważyć wykonanie zadania lub sporządzenie prototypu. Jeśli przyjęte zasady na to pozwolą, jest to najbardziej dokładny sposób szacowania, który pozwala dokonać prawdziwego postępu.
Kiedy nie masz czasu na dokładniejsze zbadanie sprawy, powinieneś najpierw precyzyjnie określić znaczenie oszacowania. Przedstaw ponownie to znaczenie jako pierwszą i ostatnią część pisemnego oszacowania. Oszacowanie przygotuj stopniowo rozkładając zadanie na mniejsze podzadania, aż do momentu, gdy czas potrzebny na wykonanie każdego małego zadania nie przekracza jednego dnia. Tak byłoby idealnie. Najważniejsze, by niczego nie pominąć, czy to dokumentacji, testowania, czasu na planowanie, czasu na komunikację z innymi grupami, czy wakacji. To wszystko jest bardzo ważne. Jeśli spędzisz część każdego dnia na zajmowaniu się półgłówkami, umieść pozycję szczegółową poświęconą temu w oszacowaniu. Dzięki temu twój szef będzie miał wgląd w to, na co przeznaczasz minimum swojego czasu i być może uzyskasz go więcej.
Znam dobrych inżynierów, którzy skrycie zawyżają ilość czasu w oszacowaniach, ale nie polecam ci tego robić, ponieważ w konsekwencji zaufanie klientów do ciebie może się zmniejszyć. Przykładowo inżynier może oszacować trzy dni dla danego zadania, o którym dobrze wie, że zajmie jeden dzień. Inżynier ten może mieć plan, by spędzić dwa dni na dokumentowaniu go lub dwa dni na pracę nad jakimś innym projektem. Jeśli jednak zadanie zostało wykonane w ciągu zaledwie jednego dnia , da się to łatwo wykryć. , a klient będzie miał wrażenie, że jesteś opieszały i zawyżasz oszacowania. O wiele lepiej jest dać właściwy pogląd na to, co tak naprawdę robisz. Jeśli dokumentacja trwa dwa razy dłużej niż pisanie kodu i oszacowanie tak stanowi, ma to ogromną zaletę, gdyż staje się widoczne dla menedżera.
Zamiast tego zawyżaj czas otwarcie. Jeśli zadanie prawdopodobnie potrwa jeden dzień, ale może potrwać dziesięć dni, jeśli twoje podejście zawiedzie, zapisz to w oszacowaniu. Jeśli nie, przynajmniej oblicz średnią ważoną szacowanego prawdopodobieństwa. Dowolny czynnik stanowiący ryzyko, który jesteś w stanie zidentyfikować i przypisać mu liczbę szacunkową powinien znaleźć się w harmonogramie. Mało prawdopodobne, że jedna osoba będzie chorować przez wszystkie tygodnie projektu. Ale przy dużym projekcie z udziałem wielu inżynierów nie obejdzie się bez zwolnień lekarskich. Podobnie rzecz się ma z wakacjami. A jakie jest prawdopodobieństwo obowiązkowych szkoleń dla wszystkich pracowników? Jeśli możesz je oszacować, zrób to. Zdarzają się oczywiście nieznane niewiadome, inaczej n.n. N.n. z definicji nie mogą być szacowane osobno. Możesz spróbować stworzyć globalną pozycję szczegółową dla wszystkich n.n. lub w inny sposób przekazać je szefowi. Nie możesz jednak pozwolić na to, by zostały przez niego niezauważone, bowiem szalenie łatwo, żeby oszacowanie stało się harmonogramem bez uwzględnienia n.n.
Pracując w zespole powinieneś sprawić, by osoby wykonujące daną pracę same dokonały jej oszacowania oraz postarać się uzyskać aprobatę całego zespołu dla oszacowań. Ludzie bardzo się różnią jeśli chodzi o umiejętności, doświadczenie, przygotowanie i pewność siebie. Katastrofa przychodzi wtedy, gdy doświadczony programista dokonuje oceny pod swoim kątem, a potem słabi programiści są oceniani na jej podstawie. Uzyskanie zgody całego zespołu co do każdego elementu oszacowania sprawi, że zrozumienie w zespole wzrośnie, jak również pozwali na mądrzejszy ponowny przydział zasobów (np. poprzez przeniesienie ciężaru pracy ze słabszych członków zespołu na tych mocniejszych).
Jeśli wchodzą w grę duże ryzyka, które nie mogą być poddane oszacowaniu, twoim obowiązkiem jest je z dostatecznie uwypuklić, aby menedżer nie był zdany na ich pastwę, a potem poczuł się wprawiony w zakłopotanie, gdy się pojawią. Przy odrobinie szczęścia w takim przypadku zostanie zrobione wszystko, co konieczne, by ryzyko zmniejszyć.
Jeśli chcesz przekonać przedsiębiorstwo by wykorzystało programowanie ekstremalne, będziesz musiał oszacować stosunkowo drobne rzeczy, a to jest zarówno bardziej przyjemne jak i bardziej wydajne.
Jak wynajdywać informacje
Sposób poszukiwań determinuje specyfika szukanych informacji.Jeśli potrzebujesz informacji o rzeczach konkretnych, które są obiektywne i łatwe do zweryfikowania, np. o poziomie poprawek programu, spytaj uprzejmie większą liczbę ludzi wyszukując to w Internecie lub pisząc na grupie dyskusyjnej. Nie szukaj w Internecie czegokolwiek, co ma posmak opinii lub subiektywnej interpretacji: stosunek absurdu do prawdy jest zbyt wysoki.
Jeśli potrzebujesz wiedzy ogólnej o czymś, co jest subiektywne i chcesz poznać historię poglądów na ten temat, idź do biblioteki (to taki materialny budynek, w którym przechowywane są książki). Na przykład by dowiedzieć się czegoś na temat matematyki, grzybów czy mistycyzmu, idź do biblioteki.
Jeśli musisz wiedzieć jak zrobić coś niebanalnego, zdobądź i przeczytaj dwie–trzy książki na ten temat. Możesz się nauczyć jak zrobić coś trywialnego, np. jak zainstalować pakiet oprogramowania z Internetu. Możesz nawet nauczyć się ważnych rzeczy, np. dobrej techniki programistycznej, ale możesz równie dobrze spędzić więcej czasu wyszukując wyniki, sortując je i próbując odgadnąć ich wiarygodność, niż trwałoby przeczytanie odpowiedniego fragmentu dobrej książki.
Jeśli potrzebujesz informacji, której nikt inny nie może znać, jak np. „czy to zupełnie nowe oprogramowanie działa na gigantycznych zbiorach danych?”, musisz jednak poszukać jej w Internecie i w bibliotece. Kiedy źródła te się wyczerpią, możesz zaprojektować eksperyment, by potwierdzić znalezione informacje.
Jeśli chcesz uzyskać opinię lub ocenę wartościującą, która uwzględnia jakieś unikalne okoliczności, porozmawiaj z ekspertem. Np. jeśli chcesz wiedzieć, czy dobrym pomysłem byłoby zbudowanie nowoczesnego systemu zarządzania bazą danych w LISP-ie, powinieneś porozmawiać z ekspertem od LISP-a oraz ekspertem od baz danych.
Jeśli chcesz wiedzieć na ile prawdopodobne jest to, że istnieje szybszy algorytm dla danego zastosowania, który nie został jeszcze opublikowany, porozmawiaj z kimś zajmującym się tą dziedziną.
Jeśli chcesz podjąć osobistą decyzję, którą tylko ty możesz podjąć, jak np. czy powinieneś założyć firmę, spróbuj zapisać listę argumentów za i przeciw temu pomysłowi. Jeśli to zawiedzie, rozważ przewidywanie. Załóżmy, że przestudiowałeś pomysł pod każdym kątem, zebrałeś potrzebne informacje i przemyślałeś wszystkie konsekwencje, argumenty za i przeciw, ale wciąż pozostajesz niezdecydowany. Musisz postąpić tak, jak ci serce dyktuje i wyłączyć myślenie. Istnieje mnóstwo technik przewidywania, które mogą pomóc ci określić własne półświadome pragnienia, ponieważ każda z nich przedstawia zupełnie losowy i wieloznaczny wzorzec, do którego twoja podświadomość przypisuje stosowne znaczenie.
Jak wykorzystywać ludzi jako źródła informacji
Szanuj czas każdej osoby i rozważaj go w kontekście swojego własnego. Zadanie komuś pytania daje o wiele więcej korzyści niż tylko uzyskanie odpowiedzi. Druga osoba dowiaduje się więcej o tobie zarówno przez przebywanie w twojej obecności jak i dzięki konkretnemu pytaniu. Ty dowiadujesz się o tej osobie w ten sam sposób i możesz poznać odpowiedź, której poszukujesz. Jest to zazwyczaj dużo ważniejsze niż twoje pytanie.
Jednak im częściej decydujesz się na taki krok, jego wartość maleje. W końcu wykorzystujesz najcenniejsze dobro, jakie osoba posiada —jej czas. Korzyści płynące z komunikacji muszą być brane pod uwagę z uwzględnieniem jej kosztów. Co więcej, konkretne koszty i korzyści, jakie można uzyskać zmieniają się w zależności od osoby. Jestem głęboko przekonany, że kierownik będący przełożonym 100 osób powinien spędzić pięć minut w miesiącu na rozmowie z każdą z nich, co będzie stanowiło około 5% jego czasu. Ale dziesięć minut może okazać się zbyt wiele, a pięć minut to zdecydowanie za dużo, jeśli firma ma tysiąc pracowników. Ilość czasu jaką powinieneś poświęcić na rozmowy z każdą osobą w firmie zależy od ich roli (bardziej niż od stanowiska). Powinieneś rozmawiać więcej ze swoim szefem niż szefem swojego szefa, ale z szefem szefa powinieneś porozmawiać chociaż trochę. Może to być nieco krępujące, ale wierzę, że twoim obowiązkiem jest porozmawiać nieco z wszystkimi przełożonymi, co miesiąc, bez względu na wszystko.
Zgodnie z podstawową zasadą, każdy czerpie korzyści rozmawiając z tobą, a i im więcej rozmawiają, tym mniej korzyści czerpią. Twoim zadaniem jest dostarczyć im tych korzyści i samemu czerpać korzyść z komunikacji z nimi, zachowując równowagę między korzyściami a czasem na to poświęconym.
Ważne jest, by szanować swój własny czas. Nawet jeśli twojego rozmówcę rozmową będzie kosztowała trochę czasu, a oszczędzi mnóstwo czasu tobie, wówczas powinieneś to zrobić, chyba że sądzisz, że jego czas jest cenniejszy niż twój, zwłaszcza biorąc pod uwagę dobro grupy.
Dość dziwnym przykładem tego jest letni staż. Po stażyście, w przypadku stanowiska o bardzo technicznym charakterze, nie można oczekiwać, aby osiągnął zbyt wiele. Można jednak oczekiwać, że będzie zadręczał wszystkich na śmierć. Więc czemu się to toleruje? Ponieważ dręczeni otrzymują coś od stażysty. Mają szansę się nieco popisać. Mają szansę usłyszeć o jakichś nowych pomysłach, być może mają szansę zobaczyć wszystko z innej perspektywy. Mogą też próbować rekrutować stażystę, ale nawet jeśli do tego nie dojdzie, dużo można zyskać.
Powinieneś prosić ludzi by podzielili się z tobą swoją mądrością i oceną kiedy tylko uczciwie wierzysz, że mają coś do powiedzenia. To im schlebia, a ty dowiadujesz się czegoś od nich i uczysz ich czegoś innego. Dobry programista nieczęsto potrzebuje rady wicedyrektora działu sprzedaży, ale jeśli tak jest, poproś o nią. Kiedyś poprosiłem, żebym mógł przysłuchać się kilku wizytom sprzedażowym by lepiej zrozumieć pracę personelu naszego działu sprzedaży. Trwało to nie dłużej niż 30 minut, ale uważam, że ten mały wysiłek zrobił wrażenie na personelu sprzedającym.
Jak dokumentować mądrze
Życie jest za krótkie, żeby pisać bzdury, których nikt nie będzie czytać: jeśli piszesz bzdury, nikt ich nie przeczyta. Zatem dość dobra dokumentacja stanowi najlepsze rozwiązanie. Menedżerowie często tego nie rozumieją, ponieważ nawet zła dokumentacja daje im fałszywe poczucie bezpieczeństwa, że nie są zależni od swoich programistów. Jeśli ktoś kategorycznie żąda, żebyś napisał naprawdę bezużyteczną dokumentację, powiedz „tak”, a po cichu zacznij rozglądać się za lepszą pracą.
Nie ma nic równie efektywnego jak umieszczenie w oszacowaniu dokładnej oceny szacunkowej co do ilości czasu, jaki jest potrzebny, by wytworzyć dobrą dokumentację w celu osłabienia zapotrzebowania na dokumentację. Prawda jest brutalna: dokumentacja, podobnie jak testowanie, może zabrać o wiele więcej czasu niż rozwijanie kodu.
Pisanie dobrej dokumentacji polega, przede wszystkim, na dobrym pisaniu. Proponuję, byś znalazł książki o pisaniu, przestudiował je, a potem ćwiczył. Ale nawet jeśli jesteś kiepskim pisarzem lub słabo władasz językiem, w którym musisz pisać dokumentację, wszystko czego potrzebujesz to złota reguła etyczna, która mówi: „nie czyń drugiemu, co tobie niemiłe”. Nie śpiesz się i naprawdę przemyśl to, kto będzie czytał twoją dokumentację, co będzie chciał z niej wynieść, i jak go tego nauczyć. Jeśli to zrobisz, będziesz ponadprzeciętnym autorem dokumentacji i dobrym programistą.
Co się tyczy samego dokumentowania kodu, w przeciwieństwie do wytwarzania dokumentów, które mogą być czytane przez nieprogramistów, najlepsi programiści, których znałem, mają wspólne przekonanie: pisz niewymagający wyjaśnienia kod i dokumentuj go w miejscach, których nie możesz uczynić klarownym samym w sobie. Są ku temu dwa dobre powody. Po pierwsze, ktokolwiek potrzebuje zobaczyć dokumentację na poziomie kodu będzie przeważnie wolał przeczytać kod samemu. Co prawda, wydaje się to łatwiejsze dla doświadczonego programisty niż dla początkującego, jednak, istotniejsze jest to, że kod i dokumentacja nie mogą być niespójne jeśli nie ma dokumentacji. Niedoskonała dokumentacja może kłamać, i to jest tysiąckrotnie gorsze.
To wcale nie sprawia, że jest łatwiej odpowiedzialnemu programiście. Jak pisać kod niewymagający wyjaśnień? Co to w ogóle znaczy? Znaczy to, że należy:
- pisać kod wiedząc, że ktoś będzie musiał go czytać;
- stosować złotą zasadę;
- wybierać rozwiązanie, które jest proste, nawet jeśli mógłbyś sobie poradzić z innym rozwiązaniem szybciej;
- poświęcać drobne optymalizacje, które zaciemniają kod;
- myśleć o czytelniku i spędzać trochę cennego czasu na uczynieniu go łatwiejszym oraz
- przenigdy nie używać nazw funkcji w rodzaju "foo", "bar" lub "ZróbTo"!
Jak pracować z kodem kiepskiej jakości
Bardzo często przychodzi nam pracować z kodem kiepskiej jakości, który napisał ktoś inny. Nie myśl o takiej osobie źle zanim postawisz się w jej sytuacji. Może ten ktoś został zupełnie świadomie poproszony by zrobić coś szybko, by sprostać presji związanej z harmonogramem. Mimo wszystko, aby pracować z niejasnym kodem musisz go zrozumieć. Będziesz potrzebował czasu na naukę, a czas ten na pewno przekroczy ramy określone w harmonogramie, jednak musisz nalegać. Zrozumienie kodu źródłowego będzie wymagało jego przeczytania. Prawdopodobnie będziesz musiał z nim eksperymentować.
To dobra okazja do stworzenia dokumentacji, choćby dla samego siebie, ponieważ działanie mające na celu udokumentowanie kodu zmusi cię do rozważenia perspektyw, których nie brałeś pod uwagę, a wynikły z tego dokument może być użyteczny. Weź wówczas pod uwagę, czego wymagałoby przepisanie części lub całości kodu. Czy tak naprawdę przepisanie jego części oszczędziłoby trochę czasu? Czy miałbyś do niego większe zaufanie, gdybyś go przepisał? Uważaj, by nie popaść w arogancję. Jeśli go przepiszesz, będzie ci łatwiej się nim posługiwać, ale czy będzie to łatwiejsze dla następnej osoby, która go przeczyta? Jak uciążliwe będzie testowanie po przepisaniu? Czy potrzeba ponownego przetestowania przeważy nad potencjalnymi korzyściami?
W jakimkolwiek oszacowaniu dotyczącym pracy z kodem, którego nie napisałeś, jakość kodu powinna wpłynąć na twoją percepcję ryzyka problemów oraz n.n.
Ważne jest, by pamiętać, że abstrakcja i hermetyzacja, dwa najlepsze narzędzia programisty, tyczą się szczególnie kiepskiego kodu. Możesz nie być w stanie zaprojektować na nowo dużego bloku kodu, ale jeśli możesz, dodaj do niego pewną ilość abstrakcji, a możesz uzyskać część korzyści płynących z dobrego projektowania bez przerabiania tego całego bałaganu. W szczególności możesz spróbować oddzielić części, które są szczególnie złe, tak by mogły być niezależnie zaprojektowane na nowo.
Jak używać kontroli kodu źródłowego
Systemy kontroli kodu źródłowego umożliwiają efektywne zarządzanie projektami. Są bardzo użyteczne dla jednej osoby i niezbędne dla grupy. Śledzą wszystkie zmiany w różnych wersjach tak, aby żaden fragment kodu nie został utracony, a zmianom mogło zostać przypisane znaczenie. Za pomocą systemu kontroli kodu źródłowego można bez obaw stworzyć jednorazowy i przeznaczony do debugowania kod, ponieważ modyfikowany kod jest starannie oddzielony od kodu oficjalnego, do którego ma dostęp zespół lub który będzie opublikowany.
Zbyt późno doceniłem korzyści płynące z systemów kontroli kodu źródłowego, ale teraz nie poradziłbym sobie bez nich nawet przy projektach jednoosobowych. Najogólniej rzecz ujmując, są one niezbędne, jeśli zespół pracuje na tej samej bazie kodu. Mają one jednak jeszcze jedną wielką zaletę: zachęcają do myślenia o kodzie jako rosnącym, organicznym systemie. Ponieważ każda zmiana jest oznaczana jako nowa korekta z nową nazwą i numerem, zaczyna się myśleć o oprogramowaniu jako widocznie postępującej serii ulepszeń. Myślę, że jest to szczególnie użyteczne dla początkujących.
Dobrą techniką używania systemów kontroli kodu źródłowego jest posługiwanie się nim przez kilka dni, będąc cały czas na bieżąco. Kod, który nie może zostać dokończony w ciągu kilku dni będzie przechowywany, ale pozostanie nieaktywny i nie będzie wywoływany, a zatem nie spowoduje problemów nikomu innemu. Popełnienie pomyłki, która opóźnia pracę kolegów z zespołu, jest poważnym błędem. Często stanowi też tabu.
Jak przeprowadzać testy jednostkowe
Testowanie jednostkowe, czyli testowanie poszczególnych fragmentów zakodowanej funkcjonalności przez zespół, który ją napisał, jest częścią kodowania, a nie czymś od niego odmiennym. Część projektowania kodu stanowi zaprojektowanie, jak będzie on testowany. Powinieneś zapisywać plan testu, nawet jeśli stanowi on jedno zdanie. Czasem test będzie prosty: „czy ten przycisk wygląda dobrze?”, a czasem złożony: ”czy ten algorytm dopasowujący zwraca dokładnie poprawne dopasowania?”.
Używaj sprawdzania asercji i programów testujących kiedy to tylko możliwe. Nie tylko wcześnie wychwytują błędy, ale są użyteczne na dalszym etapie i pozwalają eliminować tajemnice, o które w przeciwnym razie musiałbyś się martwić.
Twórcy programowania ekstremalnego obszernie piszą o efektywnym testowaniu jednostkowym. Nie pozostaje mi nic innego niż polecić lekturę ich prac.
Korzystaj z przerw kiedy jesteś w kropce
Kiedy znajdziesz się w kropce, zrób sobie przerwę. Ja czasami rozmyślam przez 15 minut kiedy utknę w miejscu, a problem w magiczny sposób rozwiązuje się kiedy do niego powracam. Sen nocny czasem spełnia tę samą funkcję na większą skalę. Chwilowa zmiana wykonywanej czynności na inną również może zadziałać.
Po czym poznać, że czas iść do domu
Programowanie komputerowe stanowi zajęcie, które jest również kulturą. Godnym ubolewania jest jednak fakt, że nie jest to kultura, która bardzo ceni sobie zdrowie psychiczne czy fizyczne. Zarówno z powodów kulturalno-historycznych (np. potrzeba pracy nocami na nieobciążonych komputerach) i z powodu przytłaczającej presji związanej z wprowadzeniem produktu na rynek oraz znikomą liczbą programistów są oni tradycyjnie przemęczeni. Nie uważam, że możesz dawać wiarę wszystkim historiom, które słyszysz, ale sądzę, że praca w wymiarze 60 godzin tygodniowo jest powszechna, a 50 godzin stanowi z pewnością minimum. Oznacza to, że często wymaga się znacznie więcej. To poważny problem dla dobrego programisty, który jest nie tylko odpowiedzialny za siebie, ale też za kolegów z zespołu.
Musisz umieć rozpoznać, kiedy iść do domu, a czasem kiedy zasugerować, by zrobili to inni. Nie ma mowy o jakichś sztywnych regułach co do rozwiązania tego problemu, podobnie jak w przypadku braku sztywnych reguł co do wychowywania dziecka. Powód jest ten sam — każda osoba jest inna.
Dla mnie ponad 60 godzin tygodniowo stanowi nadzwyczajny wysiłek, na który mogę się zdobyć przez krótki okres czasu (około jednego tygodnia) i czasem się tego ode mnie oczekuje. Nie wiem, czy to uczciwe oczekiwać od kogoś 60 godzin pracy. Nie wiem nawet, czy 40 godzin jest w porządku. Jestem jednak pewien, że nie jest mądrze pracować tak wiele, że dodatkowa godzina przynosi znikome efekty. Osobiście uważam też, że programista powinien wiedzieć, że „szlachectwo zobowiązuje” i umieć wziąć na siebie duży ciężar. Obowiązkiem programisty nie jest jednak naiwność. To smutne, że od programistów często oczekuje się, by byli naiwniakami po to, by ktoś mógł się pokazać, np. by menedżer mógł zrobić wrażenie na kierowniku. Programiści często dają się namówić, ponieważ chcą zadowolić innych i nie potrafią powiedzieć „nie”. Są cztery sposoby obrony przed tym:
- komunikuj się, na ile to możliwe, z wszystkimi w firmie tak, żeby nikt nie zwodził kierownictwa co do tego, co naprawdę się dzieje;
- naucz się szacować i układać harmonogram defensywnie i jawnie, a także daj wszystkim wgląd w to, jaki jest harmonogram i na jakim jego etapie jesteś;
- naucz się mówić „nie”, i mów „nie” jako zespół, gdy jest to konieczne
- rezygnuj, kiedy musisz.
Większość programistów to dobrzy programiści, a dobrzy programiści chcą zrobić jak najwięcej. Aby się to udało, muszą zarządzać czasem efektywnie. Jest pewna doza inercji mentalnej związanej z rozgrzewką przed przystąpieniem do problemu i zagłębieniem się w nim. Wielu programistom pracuje się najlepiej, gdy mają długie, niczym nieprzerywane okresy czasu, w których mogą wykonać rozgrzewkę i skoncentrować się. Ludzie muszą jednak spać i wykonywać inne obowiązki. Każda osoba musi znaleźć sposób, żeby uczynić zadość naturalnemu rytmowi życia jak i rytmowi pracy. Każdy programista musi robić wszystko, co konieczne, by zapewnić sobie okresy wydajnej pracy, np. zarezerwować niektóre dni, w których będzie uczestniczył tylko w spotkaniach o znaczeniu decydującym.
Ponieważ mam dzieci, staram się czasem spędzać z nimi wieczory. Rytm, jaki jest dla mnie najlepszy, to pracować długo w dzień, spać w biurze lub jego pobliżu (muszę daleko dojeżdżać z domu do pracy) a potem jechać do domu na tyle wcześnie, aby następnego dnia spędzić czas z moimi dziećmi zanim pójdą spać. Nie czuję się dobrze z takim rozwiązaniem, ale stanowi najlepszy kompromis, jaki byłem w stanie wypracować. Idź do domu, jeśli złapałeś coś zaraźliwego, a także, gdy prześladują cię myśli samobójcze. Powinieneś wziąć przerwę lub iść do domu, jeśli myślisz o dokonaniu zabójstwa dłużej niż kilka sekund. Powinieneś wysłać kogoś do domu, jeśli widać, że jego psychika nie funkcjonuje poprawnie lub ma objawy choroby psychicznej za wyjątkiem łagodnej depresji. Jeśli z powodu zmęczenia kusi cię, żeby być nieuczciwym lub zwodniczym w sposób, jaki nie jest dla ciebie normalny , powinieneś zrobić sobie przerwę. Nie używaj kokainy lub amfetaminy by przezwyciężyć zmęczenie. Nie nadużywaj kofeiny.
Jak postępować z trudnymi ludźmi
Prawdopodobnie będziesz musiał pracować z trudnymi ludźmi. Sam nawet możesz być trudną osobą. Jeśli jesteś typem osoby, która ma wiele konfliktów ze współpracownikami i zwierzchnikami, powinieneś cieszyć się niezależnością, jaką to ze sobą niesie, ale pracuj nad swoimi umiejętnościami interpersonalnymi bez poświęcania swojej inteligencji i zasad.
Może być to bardzo niepokojące dla niektórych programistów, którzy tego nie doświadczyli i których wcześniejsze doświadczenia nauczyły wzorców zachowań, które nie są użyteczne w miejscu pracy. Trudni ludzie są często przyzwyczajeni do niezgody i w mniejszym stopniu wpływa na nich presja osiągnięcia kompromisu. Kluczem jest darzyć ich odpowiednim szacunkiem. Może ci się wydawać, że to zbyt wiele, ale wciąż będzie to mniej, niż by chcieli.
Programiści muszą pracować razem jako zespół. Kiedy dochodzi do różnicy zdań, musi ona jakoś zostać rozwiązana, a uciekanie przed nią nie może trwać długo. Trudni ludzie są często bardzo inteligentni i mają coś wartościowego do powiedzenia. Istotne jest, żebyś wysłuchał i zrozumiał trudną osobę bez uprzedzeń. Niepowodzenie we wzajemnej komunikacji stanowi podstawę niezgodny, ale może być czasem pokonane przy dużej cierpliwości. Postaraj się, by wasza komunikacja była spokojna i serdeczna, nie daj się wciągnąć w większy konflikt. Po stosownym czasie potrzebnym do zrozumienia sprawy podejmij decyzję.
Nie pozwól, aby ktoś zmusił cię do czegoś, na co się nie zgadzasz. Jeśli jesteś szefem, rób to, co uważasz za najlepsze. Nie podejmuj decyzji z powodów osobistych i bądź przygotowany, by wyjaśnić powody swoich decyzji. Jeśli jesteś w zespole razem z trudną osobą, nie pozwól, żeby decyzje szefa dotknęły kogoś osobiście. Jeśli to nie zbiega się z twoimi wyobrażeniami, postąp inaczej z pełnym przekonaniem.
Trudni ludzie naprawdę się zmieniają i stają lepszymi. Widziałem to na własne oczy, ale jest to niezwykle rzadkie. Jednakże każdy ma swoje przejściowe wzloty i upadki.
Jednym z wyzwań, z jakimi musi się zmagać każdy programista, a zwłaszcza szef, to pełne zaangażowanie trudnych osób. Są one bardziej podatne na to, by uchylać się od pracy i stawiać bierny opór niż inni pracownicy.
Rozdział 3. Średniozaawansowany
Umiejętności osobiste
Jak nie stracić motywacji
Wspaniałym i zaskakującym jest fakt, że programiści są wysoko zmotywowani przez chęć tworzenia rzeczy pięknych, użytecznych i zmyślnych. Pragnienie to nie jest ani właściwe tylko programistom, ani też uniwersalne, ale jest tak silne i powszechne wśród programistów, że wyróżnia ich od pozostałych.
Ma to praktyczne i ważne konsekwencje. Jeśli programiści zostaną poproszeni o zrobienie czegoś, co nie jest piękne, użyteczne i zmyślne, będą mieć niskie morale. Można zarobić sporo pieniędzy robiąc rzeczy brzydkie, głupie i nudne, ale, koniec końców, rzeczy dające radość zarobią najwięcej pieniędzy dla przedsiębiorstwa.
Rzecz jasna, są całe gałęzie przemysłu stworzone dzięki technikom motywacyjnym, które mają tu zastosowanie. Techniki specyficzne dla programowania, które mogę wskazać brzmią następująco:
- używaj najlepszego języka dla określonego zadania;
- szukaj sposobności by zastosować nowe techniki, języki i technologii;
- staraj albo uczyć się sam, albo nauczyć czegoś innych, nawet drobnostek, w każdym projekcie.
Wreszcie, jeśli to możliwe, mierz wpływ swojej pracy w kategoriach tego, co będzie osobiście motywujące. Na przykład gdy naprawiam błąd, liczenie ilości błędów, które naprawiłem w ogóle mnie nie motywuje, ponieważ jest to niezależne od ilości błędów, które nadal istnieją i wpływa to tylko w niewielkim stopniu na łączną wartość, jaką wnoszę dla klientów przedsiębiorstwa. Odnoszenie każdego znalezionego błędu do zadowolenia klienta, jest jednak dla mnie osobiście motywujące.
Jak sprawić, żeby powszechnie nam ufano
Żeby nam ufano, musimy być godnymi zaufania. Trzeba być też widocznym. Jeśli nikt o tobie nie wie, nie obdarzy cię zaufaniem. W przypadku osób ci bliskich, np. kolegów z zespołu, to nie powinno być problemem. Wyrabiasz zaufanie do siebie poprzez to, że chłoniesz wiedzę i dzielisz się nią z osobami spoza twojego działu lub zespołu. Sporadycznie ktoś może nadużyć twojego zaufania i poprosić o wygórowaną przysługę. Nie obawiaj się tego, po prostu wyjaśnij, z czego musiałbyś zrezygnować, by taką przysługę spełnić.
Nie udawaj, że wiesz coś, czego nie wiesz. W przypadku osób, które nie są kolegami z zespołu, możesz dokonać jasnego rozróżnienia pomiędzy „nie wiem tego bez dokładnego przestudiowania tematu” a „w ogóle nie jestem w stanie do tego dojść”.
Jak znaleźć kompromis pomiędzy czasem a przestrzenią
Możesz być dobrym programistą bez studiów, ale nie możesz być dobrym średniozaawansowanym programistą nie znając podstawowej złożoności obliczeniowej. Nie musisz znać notacji „duże O”, ale osobiście uważam, że powinieneś być w stanie zrozumieć różnicę pomiędzy „czasem stałym”, „n log n” oraz „"n do kwadratu”. Możesz być w stanie intuicyjnie określić jak dokonać kompromisu między czasem a przestrzenią bez tej wiedzy, ale w przypadku jej braku nie będziesz miał solidnej podstawy do komunikacji ze swoimi kolegami.
Przy programowaniu i próbie zrozumienia algorytmu, ilość czasu potrzebna do jego wykonania, jest niekiedy funkcją wielkości danych wejściowych. Kiedy tak jest, możemy powiedzieć, że najgorszym/oczekiwanym/najlepszym przypadkiem co do czasu wykonania jest „n log n”" jeśli jest proporcjonalny do wielkości (n) razy logarytm tej wielkości. Notacja i sposób opisu może znaleźć zastosowanie dla przestrzeni zajmowanej przez strukturę danych.
Dla mnie złożoność obliczeniowa jest równie piękna i głęboka jak fizyka — mały bit przechodzi długą drogę.
Pomiędzy czasem (cyklami procesora) i przestrzenią (pamięcią) można dokonywać kompromisów. Inżynieria dotyczy kompromisu, a to jest świetny przykład. Nie zawsze jest to systematyczne. Ogólnie można jednak oszczędzić przestrzeń kodując dane ciaśniej kosztem dłuższego czasu obliczeń potrzebnego do ich odkodowania. Możesz oszczędzić czas poprzez buforowanie, czyli wykorzystywanie przestrzeni, by zapisać lokalną kopię danych kosztem konieczności zachowania spójności bufora. Możesz czasem zaoszczędzić czas zachowując więcej informacji w strukturze danych. To zazwyczaj zajmuje mało miejsca w pamięci, ale może komplikować algorytm.
Poprawianie kompromisu przestrzeń/czas może drastycznie wpływać na jedno albo drugie. Jednak zanim zaczniesz nad tym pracować, powinieneś zadać sobie pytanie czy to, co ulepszasz jest rzeczą, która najbardziej wymaga poprawy. Praca nad algorytmem cieszy, ale nie pozwól, byś przez to zapomniał, że poprawa czegoś, co nie jest problemem, nie zrobi żadnej zauważalnej różnicy i pociągnie za sobą wysiłek związany z testowaniem.
Pamięć współczesnych komputerów wydaje się tania, ponieważ w przeciwieństwie do czasu procesora nie widzisz jej zużycia dopóki „nie zderzysz się ze ścianą”, a wówczas niepowodzenie jest równoznaczne katastrofie. Są również inne ukryte koszty zużycia pamięci, takie jak twój wpływ na inne programy, które muszą pozostać rezydentne oraz czas potrzebny na alokację i zwolnienie pamięci. Rozważ to zanim zdecydujesz się zyskać na szybkości kosztem przestrzeni.
Jak wykonywać testy przeciążeniowe
Testy przeciążeniowe sprawiają radość. Z początku wydaje się, że mają na celu sprawdzić czy system działa pod obciążeniem. W rzeczywistości powszechne jest, że system faktycznie działa pod obciążeniem, ale zawodzi w jakiś sposób, gdy obciążenie jest odpowiednio duże. Nazywam to uderzeniem o ścianę lub stuknięciem. Może być od tego wiele wyjątków, ale zawsze zawierają one słowo „ściana”. Celem testów obciążeniowych jest dojść do tego, gdzie znajduje się owa „ściana, a potem jak tę ścianę odsunąć.
Plan testu obciążeniowego powinien być rozwijany na początku projektu, ponieważ to często pomaga wyjaśnić czego się oczekuje. Czy dwie sekundy na żądanie wyświetlenia strony to sromotna porażka czy miażdżący sukces? Czy 500 jednoczesnych użytkowników wystarczy? To, rzecz jasna, zależy, ale trzeba znać odpowiedź, gdy projektuje się system, który obsługuje żądanie. Testy obciążeniowe muszą modelować rzeczywistość odpowiednio dobrze, by być użytecznymi. Nie jest w rzeczywistości możliwe symulować w łatwy sposób 500 nieodpowiedzialnych i nieprzewidywalnych ludzi korzystających jednocześnie z systemu, ale można stworzyć 500 symulacji i spróbować modelować część tego, co mogą zrobić.
W testach przeciążeniowych zacznij od lekkiego obciążenia i obciążaj system w jakimś jednym wymiarze — takim jak szybkość wprowadzania danych lub rozmiar danych wejściowych — dopóki nie napotkasz ściany. Jeśli ściana znajduje się zbyt blisko, by zaspokoić twoje potrzeby ustal, który z zasobów jest wąskim gardłem (zazwyczaj jest jedno dominujące). Czy jest to pamięć, procesor, wejście/wyjście, przepustowość łącza czy rywalizacja o dostęp do danych? Potem wyobraź sobie jak możesz przesunąć ścianę. Zauważ, że przesunięcie ściany, to znaczy zwiększenie maksymalnego obciążenia, z jakim system może sobie poradzić, może nie pomóc, a właściwie zaszkodzić działaniu lekko obciążonego systemu. Zazwyczaj działanie pod dużym obciążeniem jest ważniejsze niż działanie pod lekkim.
Możliwe, że musisz uzyskać wgląd w kilka różnych wymiarów, by zbudować model mentalny, żadna pojedyncza technika nie jest wystarczająca. Np. zapisywanie w dzienniku często daje dość dobre pojęcie o czasie zegarowym pomiędzy dwoma wydarzeniami w systemie, ale jeśli nie jest dokładnie zbudowane, nie daje wglądu w wykorzystanie pamięci a nawet w rozmiar struktury danych. Podobnie we współczesnym systemie wiele komputerów i systemów oprogramowania może współpracować ze sobą. Szczególnie jeśli napotykasz ścianę (to znaczy wydajność będzie nielinearna względem wielkości danych wejściowych) te inne systemy oprogramowania mogą stanowić wąskie gardła. Wgląd w te systemy, nawet tylko poprzez obciążenie procesora na wszystkich podłączonych maszynach, może być bardzo pomocne.
Wiedza o tym gdzie znajduje się ściana ma znaczenie zasadnicze nie tylko dla jej odsunięcia, ale także dla zapewnienia przewidywalności umożliwiającej efektywne zarządzanie przedsiębiorstwem.
Jak zrównoważyć zwięzłość i abstrakcję
Abstrakcja jest kluczem do programowania. Powinieneś uważnie zdecydować w jakim stopniu chcesz z niej korzystać. Początkujący programiści w swoim entuzjazmie tworzą często więcej abstrakcji niż jest to konieczne. Jedną z oznak tego jest to, że tworzysz klasy, które nie zawierają w rzeczywistości żadnego kodu i nie robią niczego prócz służenia samej abstrakcji. Atrakcyjność tego jest zrozumiała, ale wartość zwięzłości kodu musi być przyrównywana do wartości abstrakcji. Od czasu do czasu można dostrzec pomyłkę popełnianą przez entuzjastycznych idealistów: na początku projektu definiowanych jest wiele klas, które wydają się niezwykle abstrakcyjne i można spekulować, że obsłużą każdą ewentualność. Wraz z rozwojem projektu daje o sobie znać zmęczenie, a kod robi się niechlujny. Treść funkcji stają się dłuższa niż być powinna. Puste klasy stają się trudne w dokumentowaniu, co zostaje ignorowane pod wpływem presji czasu. Końcowy rezultat byłby lepszy, gdyby energia zużyta na abstrakcję została spożytkowana na zachowanie go krótkim i prostym. Jest to forma programowania opartego na domysłach. Gorąco polecam artykuł „Zwięzłość to siła” Paula Grahama [PGSite].
Istnieje pewien dogmat związany z użytecznymi technikami takimi jak ukrywanie informacji i programowanie zorientowane obiektowo, zgodnie z którym można posunąć się za daleko. Techniki te pozwalają pisać kod abstrakcyjnie i przewidzieć zmiany. Osobiście uważam jednak, że nie powinieneś tworzyć zbyt wiele kodu opartego na domysłach. Na przykład akceptowany jest styl, w którym ukrywa się zmienną będącą liczbą całkowitą w obiekcie za metodami modyfikującymi i dostępowymi, aby sama zmienna nie była odsłonięta, tylko jej mały interfejs. To naprawdę pozwala zmieniać implementację zmiennej bez wpływu na kod ją wywołujący i jest pewnie właściwe dla twórcy biblioteki, który musi opublikować bardzo stabilny API. Ale nie uważam, że korzyść płynąca tego przewyższa koszt rozwlekłości jeśli mój zespół posiada kod wywołujący, a zatem może zakodować na nowo funkcję wywołującą równie łatwo jak tę wywoływaną. Cztery czy pięć dodatkowych linijek kodu to wysoka cena za korzyść płynącą z domysłów.
Przenośność stanowi podobny problem. Czy kod powinien być przenośny na inny komputer, kompilator, system oprogramowania lub platformę czy łatwo przesyłany? Uważam, że nieprzenośny, krótki i łatwo przesyłany fragment kodu jest lepszy niż kod długi i przenośny. Dobrym i stosunkowo łatwym rozwiązaniem jest ograniczenie się do nieprzenośnego kodu dla wyznaczonych obszarów, takich jak klasa dokonująca zapytań do bazy danych, które są właściwe dla danego DBMS.
Jak zdobywać nowe umiejętności
Nabywanie nowych umiejętności, zwłaszcza nietechnicznych, to największa radość. Większość przedsiębiorstw miałoby wyższe morale, gdyby rozumiały jak bardzo jest to motywujące dla programistów.
Ludzie uczą się wykonując jakąś czynność. Czytanie książek czy odbywanie kursów jest użyteczne. Ale czy miałbyś jakikolwiek szacunek dla programisty, który nie napisał w życiu programu? Aby nauczyć się jakiejś umiejętności musisz przybrać wyrozumiałą postawę, kiedy to możesz ćwiczyć ową umiejętność. Jeśli uczysz się nowego języka programowania, próbuj w min wykonać mały projekt zanim będziesz musiał wykonać duży. Kiedy uczysz się zarządzać projektem programistycznym, spróbuj najpierw zarządzać małym.
Dobry mentor nie zastąpi pracy samodzielnej, ale jest o wiele lepszy niż książka. Co możesz zaoferować potencjalnemu mentorowi w zamian za jego wiedzę? Przynajmniej to, że będziesz ciężko pracował tak, aby jego czas nie poszedł na marne.
Spróbuj przekonać szefa, żeby pozwolił ci odbyć szkolenie formalne, ale wiedz, że często nie jest to ani trochę lepsze niż ten sam czas spędzony na zabawie z nową umiejętnością, której próbujesz się nauczyć. Jednakże, jest łatwiej poprosić o szkolenie niż o czas na zabawę w naszym niedoskonałym świecie, mimo że wiele formalnych szkoleń polega na przesypianiu wykładów w oczekiwaniu na kolację.
Jeśli kierujesz ludźmi, zrozum jak się uczą i pomagaj im poprzez powierzanie im projektów, które mają odpowiedni rozmiar i które rozwijają umiejętności będące w kręgu ich zainteresowań. Nie zapomnij o tym, że najważniejsze umiejętności programisty to te, które nie są techniczne. Daj swoim pracownikom szansę, by się bawić i ćwiczyć odwagę, uczciwość i komunikację.
Naucz się pisać na klawiaturze
Naucz się pisać bezwzrokowo. Jest to umiejętność na poziomie średniozaawansowanym ponieważ pisanie kodu jest tak trudne, że prędkość z jaką piszesz na klawiaturze jest bez znaczenia i nie może uszczuplić czasu, jaki jest potrzebny by napisać kod, niezależnie jak dobry jesteś. Jednakże, zanim zostaniesz średniozaawansowanym programistą, prawdopodobnie spędzisz wiele czasu pisząc w języku naturalnym dla twoich kolegów i innych osób. Jest to pełen radości test twojego zaangażowania: trzeba poświęcić wiele czasu, i wcale to nie sprawia wiele radości, nauczyć się czegoś takiego. Legenda mówi, że kiedy Michael Tiemann pracował w MCC ludzie mieli zwyczaj stawać przy jego drzwiach by posłuchać szumu, jaki powodowały jego uderzenia w klawiaturę, które były tak błyskawiczne, że wręcz nie do odróżnienia.
Jak wykonać testy integracyjne
Testowanie integracyjne to testowanie stopnia integracji rozmaitych komponentów, które przeszły testy jednostkowe. Integracja jest kosztowna, co ujawnia się w testowaniu. Musisz uwzględnić czas na nią w swoim oszacowaniu i harmonogramie.
Idealnie, powinieneś zorganizować projekt tak, aby nie było takiego etapu pod jego koniec, kiedy to integracja ma miejsce w sposób jawny. O wiele lepiej jest stopniowo wszystko integrować na bieżąco w przeciągu całego projektu. Jeśli jest to nieuniknione, oszacuj to z uwagą.
Języki komunikacyjne
Istnieją pewne języki, tzn. zdefiniowane formalnie systemy składniowe, które nie są językami programowania tylko językami komunikacyjnymi – są zaprojektowane specjalnie by ułatwiać komunikację poprzez standaryzację. W roku 2003 najważniejsze spośród nich to UML, XML i SQL. Powinieneś być z nimi wszystkimi zaznajomiony, aby móc się dobrze komunikować i zdecydować kiedy ich używać.
UML to bogaty system formalny przeznaczony do tworzenia rysunków, które opisują projekty. Jego piękno polega na tym, że ma charakter zarówno wizualny jak i formalny, i jest w stanie przekazać mnóstwo informacji, jeśli tak autor, jak też odbiorcy, go znają. Musisz o nim wiedzieć, ponieważ projekty są w nim przekazywane. Istnieje wiele pomocnych narzędzi do tworzenia rysunków UML, które wyglądają bardzo profesjonalnie. W wielu przypadkach UML jest zbyt formalny, a wtedy używam prostszego stylu skrzynek i strzałek dotworzenia rysunków opisujących projekt. Ale jestem całkiem pewny, że UML jest przynajmniej tak przydatny jak studiowanie łaciny.
XML jest standardem służącym do definiowania nowych standardów. Nie jest on rozwiązaniem problemów związanych z wymianą danych, choć często jest przedstawiany jako taki. Jest raczej pożądaną automatyzacją najnudniejszej części wymiany danych, a mianowicie, przekształcania reprezentacji w linearną sekwencję i ponownego przetwarzania w strukturę. Udostępnia dobre sprawdzanie typu i poprawności, chociaż stanowi to tylko ułamek tego, co prawdopodobnie będziesz potrzebował w praktyce.
SQL jest bardzo potężnym i bogatym językiem zapytań i manipulacji danymi, który nie jest ściśle językiem programowania. Ma wiele różnych odmian, przeważnie całkowicie zależnych do produktu, które są mniej istotne niż ustandaryzowany rdzeń. SQL stanowi lingua franca relacyjnych baz danych. Być może nie pracujesz w dziedzinie, która korzysta ze zrozumienia relacyjnych baz danych, ale powinieneś mieć podstawowe pojęcie o nich oraz składni i znaczeniu SQL.
Ciężkie narzędzia
Wraz z tym, jak nasza kultura oparta na technologii się rozwija, technologia oprogramowania posuwa się od niewyobrażalnego, do badań, do nowych produktów, do ustandaryzowanych produktów, do powszechnie dostępnych i niedrogich produktów. Te ciężkie narzędzia mogą wziąć na siebie ciężkie brzemię, ale mogą onieśmielać i wymagają dużych inwestycji w ich zrozumienie. Średniozaawansowany programista musi wiedzieć jak nimi zarządzać i kiedy powinny być używane lub brane pod uwagę.
Według mojej opinii oto najlepsze ciężkie narzędzia:
- relacyjne bazy danych
- wyszukiwarki pełnego tekstu
- biblioteki matematyczne
- OpenGL
- analizatory składni XML
- arkusze kalkulacyjne
Jak analizować dane
Analiza danych to proces na wczesnym etapie rozwoju oprogramowania, kiedy to badasz działalność przedsiębiorstwa i znajdujesz wymagania, które mają zostać przekształcone w aplikację komputerową. Jest to definicja formalna, która może doprowadzić cię do przekonania, że analiza danych jest działaniem, które powinno lepiej zostać pozostawione analitykom systemów, podczas gdy ty, programista, powinieneś skupić się na pisaniu kodu, który ktoś inny zaprojektował. Jeśli przyjmiesz ściśle paradygmat inżynierii oprogramowania, może okazać się poprawny. Doświadczeni programiści zostają projektantami, a najbłyskotliwsi projektanci zostają analitykami biznesu, a zatem są upoważnieni, by myśleć o wszystkich wymaganiach co do danych i powierzają ci dobrze zdefiniowane zadania do wykonania. Nie jest to całkiem prawdą, ponieważ dane są fundamentalną wartością jeśli chodzi o programowanie. Jakiekolwiek działania podejmujesz w swoich programach, przenosisz dane lub je modyfikujesz. Analityk biznesu dokonuje analizy potrzeb w większej skali, a projektant oprogramowania ogranicza tę skalę tak, że kiedy problem trafia na twoje biurko, wydaje się, że wszystko co musisz zrobić to zastosować mądry algorytm i zacząć przenosić istniejące dane.
Ale to nie tak.
Nieważne na jakim etapie będziesz się temu przyglądać, dane są głównym zagadnieniem dobrze zaprojektowanej aplikacji. Jeśli przyjrzysz się uważnie temu, jak analityk biznesowy uzyskuje wymagania na podstawie próśb klientów, zrozumiesz, że dane odgrywają kluczową rolę. Analityk tworzy tzw. Diagram Przepływu Danych, gdzie wszystkie źródła danych zostają zidentyfikowane a i gdzie kształtuje się przepływ informacji. Dokonawszy jasnej definicji jakie dane powinny stanowić część systemu, projektant udoskonali źródła danych, w kategoriach relacji bazy danych, protokołów wymiany danych i formatów plików, tak, aby zadanie mogło być przekazane programiście. Jednakże, ten proces nie jest jeszcze zakończony, ponieważ ty, czyli programista, nawet po przeprowadzeniu tego gruntownego procesu udoskonalania danych, musisz przeanalizować dane, aby wykonać zadanie w najlepszy możliwy sposób. Sedno twojego zadania stanowi zasadnicze przesłanie Niklausa Wirtha, ojca kilku języków programowania w pracy "Algorytmy+Struktury Danych = Programy". Nigdy nie jest tak, że algorytm pozostaje sam, wykonując działania na sobie samym. Każdy algorytm ma działać na przynajmniej jednym fragmencie danych.
Zatem, skoro algorytmy nie obracają się w próżni, musisz przeanalizować dane, które zidentyfikował ktoś inny za ciebie oraz dane, które są niezbędne, by napisać twój kod. Trywialny przykład uczyni tę kwestię jaśniejszą. Implementujesz podprogram odpowiadający za przeszukiwanie dla biblioteki. Zgodnie z twoimi specyfikacjami użytkownik może wybrać książki poprzez kombinację gatunku, autora, tytułu, wydawcy, roku wydrukowania, liczby stron. Ostatecznym celem podprogramu jest wytworzenie dopuszczalnego wyrażenia SQL by przeszukać wewnętrzną bazę danych. W oparciu o te wymagania, masz kilka możliwości: sprawdzaj każdy formant po kolei używając wyrażenia "switch" lub kilka wyrażeń "if", stwórz tablicę formantów danych, sprawdzając każdy jej element by sprawdzić czy jest ustawiony, stwórz (lub użyj) abstrakcyjny obiekt formantu z którego będą dziedziczone wszystkie konkretne formanty i połącz je z silnikiem opartym na zdarzeniach. Jeśli twoje wymagania obejmują także polepszanie wydajności zapytań poprzez upewnienie się, że elementy sprawdzane są w określonym porządku, możesz uwzględnić użycie drzewa komponentów, by zbudować twoje wyrażenie SQL. Jak widzisz, wybór algorytmu zależy od tego, jakich danych chcesz użyć lub jakie dane stworzyć. Takie decyzje czynią różnicę pomiędzy wydajnym algorytmem a katastrofalnym. Jednakże, wydajność nie jest jedynym zmartwieniem. Możesz użyć tuzin zmiennych o określonej nazwie w swoim kodzie, i uczynić go wydajnym tak jak to tylko możliwe. Ale ten fragment kodu może nie być łatwy w pielęgnacji. Być może wybór właściwego kontenera dla twoich zmiennych może zachować tę samą prędkość a ponad to pozwoli twoim kolegom zrozumieć kod lepiej, gdy spojrzą na niego rok później. Ponad to, wybranie dobrze zdefiniowanej struktury danych może pozwolić im rozszerzyć funkcjonalność twojego kodu bez przepisywania go. Na dłuższą metę, twoje wybory co do danych określają jak długo twój kod przeżyje, gdy już go skończysz. Pozwól, że podam inny przykład, po prostu nieco więcej materiału do przemyśleń. Załóżmy, że twoim zadaniem jest znalezienie wszystkich słów w słowniku z liczbą anagramów większą niż trzy, gdzie anagram musi być innym słowem w tym samym słowniku. Jeśli traktujesz to w kategoriach zadania obliczeniowego, okaże się, że będziesz się trudził bez końca, próbując znaleźć wszystkie kombinacje każdego słowa a potem porównać z innymi słowami na liście. Jednakże, jeśli przeanalizujesz dane mając je "pod ręką", zdasz sobie sprawę, że każde słowo może być reprezentowane przez rekord zawierający samo słowo i posortowaną tablicę jego liter jako identyfikator. Posiłkując się tą wiedzą znalezienie anagramu oznacza po prostu posortowanie listy w dodatkowym polu i wybranie tych, które mają ten sam identyfikator. Wykonanie algorytmu "na siłę" może potrwać kilka dni, podczas gdy algorytm inteligentny może być kwestią kilku sekund. Pamiętaj o tym przykładzie następnym razem, gdy musisz stawiać czoło trudnemu do rozwiązania problemowi.
Umiejętności zespołowe
Jak zarządzać czasem rozwoju
By zarządzać czasem rozwoju, utrzymuj zwięzły i aktualny plan projektu. Plan projektu to oszacowanie, harmonogram, zbiór kamieni milowych, które służą do oznaczania postępów, oraz przydział czasu twojego zespołu lub twojego dla każdego zadania zawartego w oszacowaniu. Powinien też zawierać inne rzeczy, o których musisz pamiętać, takie jak spotkania z osobami odpowiedzialnymi za zapewnienie jakości, przygotowanie dokumentacji, zamówienie sprzętu. Jeśli jesteś w zespole, projekt powinien być rezultatem zgody wszystkich członków, zarówno na początku jak i w trakcie prac.
Plan projektu istnieje po to, by pomóc ci podejmować decyzje, a nie by pokazać jak dobrze jesteś zorganizowany. Jeśli plan projektu jest albo zbyt długi albo nieaktualny, będzie bezużyteczny przy podejmowaniu decyzji. W rzeczywistości, decyzje te dotyczą poszczególnych osób. Plan i twój osąd pozwalają zdecydować czy powinieneś przydzielać zadania jednej osobie czy innej. Kamienie milowe oznaczają twoje postępy. Jeśli używasz wymyślnego narzędzia do planowania projektów nie ulegaj pokusie tworzenia "Wielkiego Projektowania z Miejsca" dla projektu, ale wykorzystaj zwięzłość i aktualność.
Jeśli nie uda ci się osiągnąć kamienia milowego, powinieneś podjąć natychmiastowe działania takie jak poinformowanie swojego szefa, że zaplanowane ukończenie projektu przesunęła się o określoną ilość czasu. Oszacowanie i harmonogram mogły być dalekie od ideału już na samym początku, to sprawia iluzję, że możesz być w stanie nadrobić dni, o które się spóźniłeś, w dalszej części projektu. Możesz. Ale jest to równie prawdopodobne, że nie doszacowałeś tę części, jak i to, że ją przeszacowałeś. Zatem zaplanowane ukończenie projektu jest opóźnione, czy ci się to podoba czy nie.
Upewnij się, że twój plan zawiera też czas na: wewnętrzne spotkania zespołu, demonstracje, dokumentację, zaplanowane okresowe czynności, testowanie integracji, zajmowanie się osobami z zewnątrz, zwolnienia lekarskie, wakacje, pielęgnacja istniejących produktów oraz środowiska rozwojowego. Plan projektu może służyć jako sposób, by dać osobom z zewnątrz lub twojemu szefowi wgląd w to, co robisz ty lub twój zespół. Z tego powodu powinien być krótki i aktualny.
Jak zarządzać ryzykiem związanym z oprogramowaniem od stron trzecich
Projekt często zależy od oprogramowania stworzonego przez organizacje nad którymi nie masz kontroli. Istnieją ogromne ryzyka związane z oprogramowaniem od stron trzecich, które muszą być uwzględnione przez wszystkie osoby zaangażowane w projekt.
Nigdy, przenigdy, nie pokładaj nadziei w "parze". "Para" to każde domniemane oprogramowanie, co do którego zostały złożone obietnice, ale nie jest jeszcze dostępne. To najpewniejszy sposób, by wyeliminować się z biznesu. Niemądrze jest jedynie podchodzić ze sceptycyzmem do obietnic firmy programistycznej, że opublikuje określony produkt z określoną funkcją w określonym terminie: dalece mądrzej jest to całkowicie zignorować i zapomnieć, że kiedykolwiek to słyszałeś. Nigdy nie pozwól, aby zostało to zapisane w jakimkolwiek dokumencie używanym przez twoje przedsiębiorstwo.
Jeśli oprogramowanie od stron trzecich nie jest parą, wciąż jest ryzykowne, ale przynajmniej jest to ryzyko, któremu można zaradzić. Jeśli rozważasz wykorzystanie oprogramowania od stron trzecich, powinieneś poświęcić jak najwcześniej energię na jego ewaluację. Ludziom może się nie spodobać fakt, że dwa tygodnie lub dwa miesiące może potrwać ewaluacja każdego z trzech produktów pod kątem przydatności, ale musi to zostać dokonane tak wcześnie jak to tylko możliwe. Koszt integracji nie może zostać dokładnie oszacowany bez właściwej ewaluacji.
Zrozumienie przydatności istniejącego oprogramowania od stron trzecich dla konkretnego celu to wiedza ezoteryczna. Jest bardzo subiektywna i generalnie posiadają ją eksperci. Możesz zaoszczędzić sporo czasu, jeśli jesteś w stanie znaleźć tych ekspertów. Często projekt będzie oparty na systemie oprogramowania od stron trzecich do tego stopnia, że jeśli integracja zawiedzie, cały projekt się nie powiedzie. Przedstaw takie ryzyko jasno na piśmie w harmonogramie. Spróbuj mieć plan awaryjny, jak np. inny system, który może zostać wykorzystany lub możliwość napisania danej funkcjonalności samodzielnie, o ile ryzyko nie może być wcześniej wyeliminowane. Nigdy nie pozwól by harmonogram był oparty na "parze".
Jak zarządzać konsultantami
Korzystaj z pomocy konsultantów, ale nie bądź od nich zależny. Są oni wspaniałymi ludźmi i zasługują na ogromny szacunek. Ponieważ muszą przyglądać się wielu różnym projektom, często wiedzą więcej na temat konkretnych technologii i technikach programowania niż ty. Najlepszym sposobem by konsultantów wykorzystać jest zatrudnienie ich jako wewnątrzzakładowych nauczycieli, którzy mogą uczyć na przykładach.
Jednakże, zazwyczaj nie mogą być oni częścią zespołu w takim sensie jak stali pracownicy, choćby dlatego, że nie masz dość czasu by poznać ich silne strony i słabości. Ich zaangażowanie w sensie finansowym jest znacznie niższe. Mogą odejść dużo łatwiej. Mają mniej do zyskania jeśli przedsiębiorstwo odnosi sukcesy. Niektórzy z nich będą dobrzy, inni będą przeciętni, a jeszcze inni będą słabi, lecz przy odrobienie szczęścia twój wybór konsultantów nie będzie tak staranny jak wybór pracowników, więc napotkasz więcej słabych.
Jeśli konsultanci mają pisać kod, musisz przez cały czas go poddawać go uważnej analizie. Nie możesz osiągnąć końca projektu pozwalając na ryzyko, że duży blok kody nie był poddany analizie. To dotyczy wszystkich członków zespołu, naprawdę, ale będziesz dysponował obszerniejszą wiedzą dotyczącą członków zespołu, którzy są najbliżej ciebie.
Jak komunikować się w dostatecznym stopniu
Rozważ uważnie koszt spotkania: jego koszt jest równy jego trwaniu pomnożonemu przez liczbę uczestników. Spotkania są niekiedy konieczne, ale mniej zazwyczaj znaczy lepiej. Jakość komunikacji na małych spotkaniach jest wyższa i ogólnie mniej czasu jest marnowane. Jeśli choćby jedna osoba jest znudzona na spotkaniu uznaj to za znak, że spotkanie powinno być mniej liczne.
Powinno się dołożyć wszelkich starań, by zachęcić uczestników do komunikacji drogą nieformalną. Więcej użytecznej pracy jest wykonywane podczas lunchu z kolegami niż w innych okolicznościach. Szkoda, że większość przedsiębiorstw nie dostrzega i nie popiera tego faktu.
Jak uczciwie zachować swoje zdanie i unikać złych tego konsekwencji
Różnica zdań to świetna okazja, by dokonać dobrej decyzji, ale trzeba tu postępować z delikatnością. Miejmy nadzieję, że czujesz, iż wyraziłeś swoje poglądy w należyty sposób i zostałeś wysłuchany, zanim podjęto decyzję. W tym przypadku nie pozostaje nic do dodania i powinieneś zdecydować czy będziesz się opowiadał za decyzją nawet jeśli się z nią nie zgadzasz. Jeśli możesz poprzeć tę decyzję, nawet jeśli się z nią nie zgadzasz, powiedz to. To pokazuje jak jesteś cenny, ponieważ jesteś niezależny i nie będziesz potakiwaczem, ale masz szacunek do tej decyzji i jesteś też graczem zespołowym
Czasami decyzja, z którą się nie zgadzasz zostanie podjęta w przypadku, gdy osoby ją podejmujące nie skorzystały w pełni z twojej opinii. Powinieneś wówczas ocenić, czy poruszyć tę kwestię opierając się na korzyści dla przedsiębiorstwa lub grona. Jeśli jest to drobna pomyłka w twoim odczuciu, może nie warto zastanawiać się nad nią jeszcze raz. Ale jeśli jest to duża pomyłka wedle twojej opinii, wówczas musisz przedstawić argumenty.
Zazwyczaj, nie jest to problemem. W niektórych stresujących okolicznościach i w przypadku niektórych typów osobowości może to doprowadzić do tego, że sprawy zostaną potraktowane osobiście. Np. niektórzy bardzo dobrzy programiści nie mają dość pewności siebie, by sprzeciwić się decyzji nawet jeśli mają dobry powód by wierzyć, że jest ona niesłuszna. W najgorszych okolicznościach osoba podejmująca decyzję czuje się niepewna i bierze to do siebie jako podważanie jego autorytetu. Najlepiej jest pamiętać, że w takiej sytuacji ludzie reagują przy pomocy gadziej części ich mózgów. Powinieneś przedstawić swój argument na osobności i spróbować pokazać jak nowa wiedza zmienia podstawę, na której podjęto decyzję.
Niezależnie od tego, czy decyzja została cofnięta, musisz pamiętać, że nigdy nie będziesz w stanie powiedzieć "Przecież ci mówiłem" ponieważ alternatywna decyzja została w pełni zbadana.
Osąd
Jak dokonać kompromisu pomiędzy jakością a czasem rozwoju
Rozwijanie oprogramowania to zawsze kompromis pomiędzy tym co projekt może zrobić a ukończeniem go. Ale możesz być poproszony, by dokonać kompromisu między jakością a szybkością wdrożenia projektu w sposób, jaki urąga twojej wrażliwości jako inżyniera lub w sensie biznesowym. Np. możesz zostać poproszony by zrobić coś, co stanowi złą praktykę inżynierii oprogramowania i doprowadzi do wielu problemów z pielęgnacją.
Jeśli się to zdarzy, twoim pierwszym obowiązkiem jest poinformowanie twojego zespołu i jasne wyjaśnienie kosztów obniżenia jakości. W końcu, twoje zrozumienie tego problemu jest lepsze niż twojego szefa. Wyraź się jasno co do tego, jakie są straty i korzyści oraz jakim kosztem stracony dystans będzie odrobiony w następnym cyklu. Wgląd zapewniony przez dobry plan projektu może okazać się w tym pomocny. Jeśli kompromis co do jakości wpływa na wysiłki związane z zapewnieniem jakości, wskaż to (zarówno szefowi jak i osobom odpowiedzialnym za zapewnienie jakości). Jeśli kompromis co do jakości doprowadzi do większej ilości raportowanych błędów po zakończeniu okresu zapewnienia jakości, również wskaż i to.
Jeśli szef będzie nalegał, powinieneś spróbować wyizolować tandetność produktu do formy osobnych komponentów, które możesz zgodnie z planem przepisać lub poprawić w następnym cyklu. Wyjaśnij to swojemu zespołowi, aby mogli to zaplanować.
NinjaProgrammer na Shlashdot nadesłał następująca perełkę:
Pamiętaj, że dobry projekt będzie odporny na słabe implementacje kodu. Jeśli dobre interfejsy i abstrakcje istnieją w całym kodzie, wówczas ewentualne przepisywanie będzie dalece mniej bolesne. Jeśli trudno jest napisać jasny kod, który trudno naprawić, zastanów się co jest nie tak z projektowaniem kodu, który jest tego powodem.
Jak zarządzać zależnością systemów oprogramowania
Współczesne systemy oprogramowania zazwyczaj zależy od dużej liczby komponentów, które mogą nie być pod twoją kontrolą. To zwiększa wydajność poprzez synergię i ponowne wykorzystanie. Jednakże, każdy komponent niesie ze sobą pewne problemy:
- jak naprawisz błędy w tym komponencie?
- czy dany komponent ogranicza cię do konkretnego systemu sprzętowego lub oprogramowania?
- co zrobisz, jeśli komponent całkiem zawiedzie?
Zawsze najlepiej jest hermetyzować komponent w jakiś sposób aby został odizolowany i aby mógł być zamieniony. Jeśli komponent okazuje się całkowicie niezdolny do pracy, możesz być w stanie przenieść się na inny, ale możesz być zmuszony napisać swój własny. Hermetyzacja nie jest równoznaczna przenośności, ale sprawia, że przesyłanie jest łatwiejsze, co jest niemal równie dobre.
Posiadanie kodu źródłowego komponentu zmniejsza ryzyko o współczynnik rzędu czterech. Z pomocą kodu źródłowego możesz ewaluować go łatwiej, łatwiej debugować, łatwiej znaleźć obejścia i łatwiej dokonać poprawek. Jeśli dokonujesz poprawek, powinieneś przekazać je właścicielowi komponentu aby dodano poprawki do oficjalnej wersji, w przeciwnym razie będziesz musiał w sposób dla ciebie niewygodny pielęgnować wersję nieoficjalną.
Jak zdecydować czy oprogramowanie jest zbyt niedojrzałe
Używanie oprogramowania napisanych przez innych jest jednym z najbardziej efektywnych sposobów, aby szybko zbudować solidny system. Nie powinno się do tego zniechęcać, ale ryzyka z tym związane muszą być zbadane. Jednym z największych ryzyk jest okres "zapluskwienia" i niemal zupełnej niezdolności do działania, która jest często związana z oprogramowaniem zanim się ono stanie dojrzałe, poprzez jego wykorzystanie, do formy produktu zdatnego do użycia. Zanim rozważysz integrację z systemem oprogramowania, czy to stworzonego w firmie, czy od stron trzecich, bardzo ważne jest rozważyć czy jest naprawdę wystarczająco dojrzały by go używać. Oto dziesięć pytań, które powinieneś sobie zadać co do niego:
- Czy jest on "parą"? (Obietnice są bardzo niedojrzałe).
- Czy istnieje dostęp do tradycji dotyczącej użytkowania oprogramowania?
- Czy jesteś pierwszym użytkownikiem?
- Czy istnieje silna motywacja do jego kontynuacji?
- Czy zostały poczynione wysiłki odnośnie jego pielęgnacji?
- Czy przetrwa ono porzucenie go przez obecnych opiekunów?
- Czy istnieje sprawdzona alternatywa, która choćby w połowie jest tak dobra?
- Czy jest znane dla twojego grona lub przedsiębiorstwa?
- Czy jest pożądane dla twojego grona lub przedsiębiorstwa?
- Czy możesz zatrudnić ludzi by pracowali nad tym, nawet jeśli jest złe?
Drobne rozważenie tych kryteriów przedstawia ogromną wartość dobrze ugruntowanego darmowego oprogramowania i oprogramowania "open-source" w redukowaniu ryzyka dla przedsiębiorców.
Jak dokonać wyboru "kup lub zbuduj"
Przedsiębiorstwo lub projekt, który usiłuje osiągnąć coś jeśli chodzi o oprogramowanie musi stale dokonywać tzw. decyzji "kup lub zbuduj". Ten zwrot jest niezbyt szczęśliwy i to w dwójnasób: zdaje się ignorować oprogramowanie typu "open-source" i darmowe oprogramowanie, które nie jest konieczne kupowane. Co ważniejsze, powinno się to nazywać decyzją "zdobądź i zintegruj" wobec innej decyzji "zbuduj tutaj i zintegruj" ponieważ koszt integracji musi być wzięty pod uwagę. To wymaga świetnego połączenia pomyślunku biznesowego, kierowniczego oraz inżynieryjnego.
- Jak dobrze twoje potrzeby spełniają potrzeby tych, dla których został zaprojektowany?
- Jaką część tego, co kupujesz, będziesz potrzebował?
- Jaki jest koszt ewaluowania integracji?
- Jaki jest koszt integracji?
- Czy kupienie zwiększy czy zmniejszy długoterminowe koszty pielęgnacji?
- Czy zbudowanie go da ci taką pozycję biznesową, w której nie chcesz się znaleźć?
Powinieneś dobrze przemyśleć zanim zbudujesz coś, co jest wystarczająco duże by służyć jako podstawa dla całkowicie innego przedsięwzięcia. Takie pomysły są często podsuwane przez radosnych i optymistycznych ludzi, którzy mogą wiele wnieść do twojego zespołu. Jeśli ich pomysł jest frapujący, możesz sobie zażyczyć zmianę biznesplanu, ale nie inwestuj w rozwiązanie większe niż firma bez świadomego przemyślenia sprawy.
Po rozważeniu tych pytań, powinieneś być może przygotować dwa plany projektu w wersji roboczej, jeden na ewentualność zbudowania, drugi na ewentualność zakupienia. To zmusi cię do rozważenia kosztów integracji. Powinieneś również rozważyć długoterminowe koszty pielęgnacji obu rozwiązań. By oszacować koszty integracji, będziesz musiał dokonać rzetelnej ewaluacji oprogramowania zanim je kupisz. Jeśli nie możesz jej dokonać, przyjmiesz niepotrzebne ryzyko kupując je i powinieneś zdecydować, aby odstąpić od kupienia tego konkretnego produktu. Jeśli jest kilka możliwości zakupu do rozważenia, jakaś część energii musi zostać wykorzystana na ewaluację każdej z nich.
Jak rozwijać się zawodowo
Przyjmij na siebie obowiązek, który wykracza poza twoje uprawnienia. Graj rolę, jakiej pragniesz. Wyraź swoją wdzięczność za wkład ludzi stojących za sukcesem większej organizacji, jak i za rzeczy, które pomogły tobie osobiście.
Jeśli chcesz zostać kierownikiem zespołu, namawiaj do wytworzenia konsensusu. Jeśli chcesz zostać managerem, weź odpowiedzialność za harmonogram. Możesz zazwyczaj zrobić to w sposób wygodny pracując z kierownikiem lub managerem, ponieważ to zwalnia ich z wzięcia na siebie większej odpowiedzialności. Jeśli jest to za wiele, zrób choć trochę za jednym razem.
Oceniaj samego siebie. Jeśli chcesz stać się lepszym programistą, zapytaj kogoś, kogo podziwiasz, jak możesz stać się taki jak on. Możesz też zapytać swojego szefa, który wie mniej, ale ma większy wpływ na twoją karierę.
Zaplanuj sposoby, by uczyć się nowych umiejętności, zarówno trywialnych technicznych, jak np. nowego systemu oprogramowania, jak i trudnych, społecznych, takich jak np. dobrego pisania, poprzez integrowanie ich w swojej pracy.
Jak oceniać kandydatów podczas rozmowy kwalifikacyjnej
Do oceny potencjalnych pracowników nie poświęca się należytej energii. Zły wybór przy zatrudnieniu, tak jak zły wybór małżonka, jest okropny. Znaczącą cześć energii powinno się poświęcić rekrutacji, aczkolwiek rzadko tak się zdarza.
Istnieją różne style prowadzenia rozmowy kwalifikacyjnej. Niektóre przypominają tortury, zaprojektowane z myślą o tym, aby poddać kandydata ogromnemu stresowi. Służy to cennemu celowi ewentualnego ujawnienia wad charakteru i słabości pod wpływem presji. Kandydaci nie są wcale uczciwsi wobec przeprowadzającego rozmowę kwalifikacyjną niż wobec siebie samych, a ludzka zdolność do samooszukiwania jest zdumiewająca.
Powinieneś, minimalnie, poświęcić kandydatowi odpowiednik ustnego egzaminu na temat umiejętności technicznych przez dwie godziny. Wraz z praktyką, będziesz w stanie szybko określić co wie i równie szybko wycofać się z tego, czego nie wie, aby zakreślić tę granicę. Kandydaci uszanują to. Kilkakrotnie zdarzyło mi się słyszeć, że kandydaci mówili, iż jakość egzaminu była jedną z motywacji przy wyborze przedsiębiorstwa. Dobrzy pracownicy chcą być zatrudniani ze względu na ich umiejętności, a nie gdzie ostatnio pracowali czy do jakiej szkoły uczęszczali, lub na podstawie jakichś innych drugorzędnych cech.
Przeprowadzając rozmowę, powinieneś również ocenia zdolność do uczenia, co jest dalece ważniejsze niż to, co kandydat wie. Powinieneś również uważać na symptomy, które zdradzają trudnych ludzi. Możesz być w stanie poznać to porównując notatki po zakończeniu rozmowy, ale w ferworze rozmowy jest to trudne. To, jak ludzie komunikują się i pracują z innymi, jest ważniejsze niż czy są na bieżąco z najnowszym językiem programowania.
Czytelnik może mieć dużo szczęścia, jeśli jest w stanie użyć testu typu "zrób to sam w domu" względem kandydatów. Ma to tę zaletę, że może wykryć kandydatów, którzy potrafią się dobrze zaprezentować, ale nie potrafią pisać kodu – wiele jest takich osób. Osobiście nie stosowałem tej techniki, ale brzmi ona rozsądnie.
Wreszcie, rozmowa kwalifikacyjna to proces sprzedaży. Powinieneś dobrze sprzedać swoje przedsiębiorstwo lub projekt kandydatowi. Jednakże, rozmawiasz z programistą, więc nie próbuj koloryzować prawdy. Zacznij od kiepskich rzeczy, a zakończ mocno na rzeczach dobrych.
Skąd wiedzieć, kiedy zastosować wymyślną informatykę
Istnieje obszerna wiedza z zakresu algorytmów, struktur danych, matematyki i innych odjazdowych rzeczy, które większość programistów zna, ale rzadko używa. W praktyce, te wspaniałe rzeczy są zbyt skomplikowane, a najogólniej zbyteczne. Nie ma sensu poprawianie algorytmu w przypadku gdy większość twojego czasu jest poświęcane np. na niewydajne wywołania bazy danych. Niewdzięczna część programowania polega na sprawianiu, że systemy porozumiewają się ze sobą i używaniu bardzo prostych struktur danych by zbudować dobry interfejs użytkownika.
Kiedy zaawansowane technologie są właściwymi? Kiedy powinieneś sięgnąć po książkę by osiągnąć coś, co nie jest szablonowym algorytmem? Czasem jest użyteczne by się do tego uciec, ale powinno być to ocenione z uwagą.
Trzy najważniejsze okoliczności dla potencjalnej techniki informatycznej to:
- Czy jest dobrze hermetyzowana tak, żeby ryzyko dla innych systemów i ogólny wzrost złożoności oraz kosztów pielęgnacji były niskie?
- Czy korzyść płynąca z niej jest zdumiewająca (np. współczynnik rzędu dwóch w dojrzałym systemie lub współczynnik dziesięciu w nowym)?
- Czy będziesz w stanie przetestować i ocenić ją efektywnie?
Jeśli dobrze odizolowany algorytm, który używa nieco wymyślnego algorytmu może zmniejszyć koszt sprzętowy lub zwiększyć wydajność o współczynnik rzędu dwóch całego systemu, byłoby zbrodnią go nie rozważyć. Jednym z kluczy w dyskusji na temat takiego podejścia jest wykazanie, że ryzyko jest naprawdę niskie, gdyż proponowana technologia prawdopodobnie została dokładnie przestudiowana, jedynym problemem jest ryzyko integracji. Tutaj doświadczenie i osąd programisty mogą naprawdę wejść w synergię z wymyślną technologią by uczynić integrację łatwą.
Jak rozmawiać z „nieinżynierami”
Inżynierowie, a programiści w szczególności, są ogólnie postrzegani przez kulturę popularną jako odmienni w stosunku do pozostałych ludzi. To sugeruje, że inni różnią się od nas. Warto jest mieć na względzie podczas komunikowania się z nie inżynierami: zawsze powinieneś rozumieć odbiorców.
„Nieinżynierowie” są mądrzy, ale nie ugruntowani w tworzeniu rzeczy technicznych w takim stopniu jak my. My tworzymy rzeczy. Oni je sprzedają, obsługują, liczą i zarządzają nimi, ale nie są ekspertami w tworzeniu ich. Nie są tak dobrzy we wspólnej pracy w zespole jak inżynierowie (istnieją bez wątpienia wyjątki od tego). Ich umiejętności społeczne są generalnie równie dobre, jeśli nie lepsze, od umiejętności inżynierów w środowiskach nie będących zespołem, ale ich praca nie zawsze wymaga tego, aby praktykowali zażyłą, precyzyjną komunikację i uważny podział zadań tak jak my.
Nie inżynierowie mogą chcieć się przypodobać i mogą być wobec ciebie onieśmieleni. Tak jak my, mogą powiedzieć "tak" nie mając tego w ogóle na myśli, tak, by sprawić ci przyjemność albo dlatego, że są nieco tobą wystraszeni, a potem okazuje się, że było to bez pokrycia.
„Nieprogramiści” są w stanie zrozumieć sprawy techniczne, ale nie mają tego, co nawet dla nas jest tak trudne – techniczny osąd. Rozumieją jak działa technologia, ale nie są w stanie zrozumieć dlaczego określone podejście zajmie trzy miesiące a inne trzy dni (w końcu programiści są według anegdot również beznadziejni w tego rodzaju ocenie). To stanowi świetną okazję by wejść z nimi w synergię.
Rozmawiając ze swoim zespołem będziesz, bez namysłu, używał skrótowych określeń, języka, który jest efektywny ponieważ macie wiele wspólnych doświadczeń jeśli chodzi o technologię ogólnie, a waszego produktu w szczególności. Wymaga to nieco wysiłku, aby nie używać tych skrótów w z tymi, którzy nie posiadają tego wspólnego doświadczenia, zwłaszcza gdy członkowie twojego zespołu są obecni. To słownictwo tworzy mur pomiędzy tobą a tymi, którzy go nie używają, oraz, co gorsza, sprawia, że tracą czas.
W przypadku twojego zespołu, podstawowe założenia i cele nie muszą być często przypominane, a większość rozmów skupia się na szczegółach. Z osobami z zewnątrz, jest dokładnie odwrotnie. Mogą nie rozumieć rzeczy, które uznajesz za oczywiste. Skoro je za takie uważasz, i nie powtarzasz ich, możesz zakończyć rozmowę z osobą spoza myśląc, że rozumiecie się nawzajem, podczas gdy tak naprawdę istnieje duże nieporozumienie. Powinieneś zakładać, że nie porozumiesz się odpowiednio i obserwować uważnie, by znaleźć przyczynę tej niewłaściwej komunikacji. Spróbuj sprawić aby podsumowali lub parafrazowali to, co mówisz, by upewnić się, że rozumieją. Jeśli masz sposobność, by często spotkać się z nimi, poświęć trochę czasu aby zapytać, czy komunikujesz się z nimi efektywnie i jak poprawić komunikację. Jeśli istnieje problem w porozumieniu, spróbuj zmienić swoje postępowanie zanim staniesz się sfrustrowany z ich powodu.
Uwielbiam pracować z nie inżynierami. To dostarcza świetnych okazji by uczyć się i nauczyć czegoś innych. Możesz często pokazywać coś na przykładzie, w kategoriach jasności twojej komunikacji. Inżynierowie są wyćwiczeni w tym, by wydobywać porządek z chaosu, by wydobywać jasność z niezrozumienia, a nie inżynierowie lubią to w nas. Ponieważ mamy techniczny osąd i potrafimy zazwyczaj zrozumieć kwestie biznesowe, możemy często znaleźć proste rozwiązanie problemu.
Często nie inżynierowie proponują rozwiązania, które, ich zdaniem, ułatwią nam życie i robią to z uprzejmości i pragnienia, by postępować słusznie, podczas gdy w rzeczywistości istnieje o wiele lepsze ogólne rozwiązanie, które może zostać dostrzeżone poprzez synergię oglądu osoby z zewnątrz i twojego technicznego osądu. Osobiście podoba mi się Programowanie Ekstremalne ponieważ odnosi się ono do tej nieskuteczności, łącząc szybko oszacowanie z pomysłem, sprawia, że jest łatwiej znaleźć pomysł, który jest najlepszym połączeniem kosztu i korzyści.
Rozdział 4. Zaawansowany
Osąd technologiczny
Jak odróżnić trudne od niemożliwego
Nasza praca polega na wykonywaniu tego, co trudne, i dostrzeganiu tego, co niemożliwe. Z punktu widzenia większości zawodowych programistów rzeczy niemożliwe to takie, których nie można rozwinąć z prostego systemu lub oszacować. Zgodnie z tą definicjąniemożliwejest więc to, co nazywamy badaniami. Duża ilość zwykłej pracyjest trudna do wykonania, ale niekoniecznie niemożliwa.
Rozróżnienie to nie jest niemądre, ponieważ możesz zostać poproszony o wykonanie rzeczy praktycznie niemożliwej z naukowego punktu widzenia albo z perspektywy inżynierii oprogramowania. Wówczas twoim obowiązkiem jest pomoc przedsiębiorcy w znalezieniurozsądnegorozwiązania, które będziezaledwie trudne i pozwala osiągnąć jak najwięcej pożądanych rezultatów. Rozwiązanie jest zaledwie trudne, gdy może być pewnie ujęte w formie harmonogramu, a ryzyka są zrozumiałe.
Niemożliwym jest spełnić bardzo ogólne wymagania, takie jak „Zbuduj system, który obliczy najbardziej atrakcyjną fryzurę i kolor włosów dla dowolnej osoby”. Jeśli wymagania te zostaną ujęte bardziej precyzyjnie, np. „Zbuduj system, który obliczy atrakcyjną fryzurę i kolor włosów dla danej osoby, wyposaż go w funkcję podglądu i dokonywania zmian oraz zapewnij satysfakcję klienta w oparciu o oryginalną stylizację, dzięki której zarobimy dużo pieniędzy”,zadanie stanie się zaledwie trudne. Nie da się osiągnąć sukcesu, jeśli nie zostanie on konkretnie zdefiniowany.
Jak wykorzystać języki wbudowane
Wbudowywanie języka programowania w system ma dla programisty posmak niemalże erotycznej fascynacji. Jest to jedno z najbardziej kreatywnych działań, jakie można podjąć.Dzięki niemu system staje się niezwykle potężny. Wbudowany język programowana pozwala wykorzystaćnajbardziej kreatywne i niemal prometejskie umiejętności systemu oraz zamienia gow twojego przyjaciela.
Języki wbudowane występują we wszystkich najlepszychna świecie edytorach tekstu, gdzieich zastosowaniemoże pomóc odbiorcy docelowemu opanować dany język. Oczywiście, wykorzystanie języka, podobnie jak w edytorze tekstu, może być opcjonalne; korzystać z niego nie muszą wówczas wszyscy, lecz tylko wtajemniczeni.
Zarówno mnie, jak i wielu innym programistom zdarzyło się wpaść w pułapkę tworzenia języka wbudowanego specjalnego przeznaczenia. Ja wpadłem w nią dwukrotnie. Istnieje już wiele języków zaprojektowanych konkretnie jako języki wbudowane, dlatego powinieneś się dobrze zastanowić zanim stworzysz nowy język tego typu.
Rzeczywiste pytanie, jakie trzeba sobie zadać przed wbudowaniem języka brzmi: „Czy działa on zgodnie z kulturą odbiorców, czy wbrew niej?”. Czy będzie pomocny, jeśli jegoodbiorcami mają byćwyłącznie nieprogramiści? Jeśli odbiorcami są wyłącznie programiści, czy woleliby może interfejs programowania aplikacji (API)? I jaki język wybrać? Programiści nie chcą uczyć się nowego języka, który nie jest powszechnie używany.Jeśli jednak będzie on związanyz ich kulturą to nie będą musieli poświęcać wiele czasu na jego naukę. Tworzenie nowego języka stanowi przyjemność, lecznie możemy dopuścić, by przesłoniła nampotrzeby użytkownika. Jeśli nie musimy sprostaćnaprawdę nietypowymwymaganiomi koncepcjom, może warto użyć istniejącego języka i wykorzystać to, że użytkownicy są już z nim zaznajomieni?
Wybór języka
Samotny programista, który uwielbia swoją pracę (haker) może wybrać język stosowny dla danego zadania,jednakwiększość zawodowych programistów ma na ten wybór niewielki wypływ. Zazwyczaj o tej kwestii decydują niezbyt zorientowani szefowie, których wybór podyktowany jest bardziej polityką firmy niż wiedzą technologiczną, i brakuje im odwagi, by wypromowaćjakieś niekonwencjonalne narzędzie, nawet jeśliwiedzą, często z pierwszej ręki, że to mniej rozpowszechnione narzędzie jest najlepsze. W innych przypadkach prawdziwa korzyść płynącą z jedności zespołu, i w pewnym stopniu ze zgody w większej społeczności, wyklucza możliwość dokonania wyboru przez jedną osobę. Menedżerami często kieruje potrzeba zatrudnienia programistów z doświadczeniem w danym języku. Bez wątpienia starają się działać w najlepszym interesie projektu lub przedsiębiorstwa i za to należy im się za to szacunek. Ja osobiście wierzęjednak, że jest to najbardziej marnotrawna i błędna powszechna praktyka, z jaką możesz się spotkać.
Oczywiście, rzeczywistość nigdy nie jest jednowymiarowa.Nawet jeśli rdzeń języka zostałnarzucony i jest poza twoją kontrolą, często zdarza się, że narzędzia i inne programy mogą i powinny zostaćnapisane w innym języku. Jeśli język ma zostać wbudowany (co zawsze należy rozważyć),jego wybór powinien w dużym stopniu zależeć od kultury użytkowników.Należy ją wykorzystaćby przysłużyć się przedsiębiorstwu lub projektowi poprzez użycie najlepszego języka dla danego zadania i w ten sposób uczynić pracę bardziej interesującą.
Języki programowania powinno się nazywać w rzeczywistości notacjami w tym sensie, że opanowanie któregoś z nich nie jest wcale tak trudne jak nauką języka naturalnego. Dla początkujących i ludzi z zewnątrz „nauka nowego języka” wydaje się zniechęcającym zadaniem, ale jeśli znasz już trzy językito nauka kolejnego jest tylko kwestią zapoznania się z dostępnymi bibliotekami.Częstopostrzegamy duży system, którego komponenty zostały napisane w trzech lub czterech językach jakoniechlujny miszmasz, jednak moim zdaniem taki system jest w wielu przypadkach silniejszy niż system w jednym języku, i to pod kilkoma względami:
- komponenty napisane w różnych notacjach muszą być ze sobą luźno powiązane (chociażinterfejsy mogą nie być zbyt przejrzyste),
- przepisując każdy komponent z osobna można łatwo rozwinąćnowyjęzyk/platformę,
- możliwe jest, że niektóre moduły systemu są faktycznie aktualne.
Niektóre z tych efektów mogą mieć jedynie znaczenie psychologiczne, ale psychologia jest ważna. W końcu koszty tyranii języka przewyższają jego zalety.
Dokonywanie mądrych kompromisów
Jak zwalczyć presję związaną z harmonogramem
Presja związana z wprowadzeniem produktu na rynek to presjaszybkiegodostarczenia produktu. To dobra i do pewnego stopnia zdrowa sytuacja, ponieważ odzwierciedla rzeczywistość finansową. Presja związana z harmonogramem to presja, by dostarczyć coś szybciej niż jest to możliwe, a przez to stanowi marnotrawną, niezdrową i zbyt powszechną praktykę.
Presja związana z harmonogramem istnieje z kilku powodów. Osoby, które powierzają zadania programistom nie zdają sobie sprawy z tego, jak silną mamy etykę pracy i ile radości sprawia nam nasz zawód. Być może dlatego, że dokonują oni projekcji swoich własnych zachowań na nas i wierzą, że jeśli poproszą, abyśmy zrobili cośwcześniej to będziemy pracowali ciężej, aby ten cel osiągnąć. Pewnie tak jest, ale efekt jest bardzo mały, a straty bardzo duże. Ponadto zleceniodawcyzupełnie nie mają wglądu w to, co jest niezbędne do stworzenia oprogramowania. Nie będąc w stanie tego dostrzec, i nie mogąc wykonać tej pracy samemu, przełożeni dostrzegają jedynie presję związaną zwprowadzeniem produktu na rynek i ciągle przypominają o niejprogramistom.
Kluczem do zwalczenia presji związanej z harmonogramem jest po prostu przekształcenie jej w presję związaną z wprowadzeniem produktu na rynek. Można to zrobić umożliwiając innym wgląd w związek między możliwą do wykonania pracą a produktem. Uczciwe, szczegółowe, a nade wszystkozrozumiałe oszacowanie niezbędnej pracy będzie na to najlepszym sposobem. Ma to tę dodatkową zaletę, że pozwala na podjęcie dobrych decyzjico do kompromisów związanych z funkcjonalnością.
Praca przypominaniemal nieściśliwy płyn i oszacowanie powinno tę kluczową uwagę jasno uwzględniać. Nie da się zrobić więcej niż pozwala na to czas, podobnie jak niemożna wypełnić pojemnika wodąponad jego objętość. W pewnym sensie programista nigdy nie powinien mówić „nie”, ale powinien zapytać: „Co jesteś w stanie poświęcić, aby otrzymać pożądane rezultaty?”. Dzięki jasnym oszacowaniomszacunek do programistów wzrasta. Tak postępują inni profesjonaliści. Ciężka praca programistów będzie widoczna. Ustanowienierealistycznego harmonogramu będzie aż do bólu oczywiste dla każdego. Programiści nie mogą być mamieni. To oznaka braku szacunku,aproszenie ich ozrobienie czegoś nierealistycznego jest demoralizujące. Programowanie ekstremalne rozwija tę koncepcję i buduje na jej podstawieproces.Mam nadzieję, że każdy czytelnik będzie miał dość szczęścia, by z niego skorzystać.
Jak zrozumieć użytkownika
Twoim obowiązkiem jest zrozumieć użytkownika i pomóc w tym twojemu szefowi. Ponieważ użytkownik nie jest ściśle zaangażowany w tworzenie produktu w takim stopniu jak ty, jego zachowanie jest nieco inne:
- użytkownikzazwyczaj udziela krótkich wypowiedzi,
- ma swoje własne obowiązki: będzie głównie myślał o drobnych usprawnieniach, nie o dużych,
- nie mawglądu w to, kim jestogół użytkowników produktu.
Twoim obowiązkiem jest dostarczenie użytkownikowi produktu, jakiego naprawdę potrzebuje, a nie tego, co takim mu się tylko wydaje. Lepiej jednak zaproponować spełnienie życzeń użytkownika, a następnie przekonać go do naszego własnego rozwiązania, na które klient sam by nie wpadł, przed rozpoczęciem pracy. Twojeprzekonanie co do własnychpomysłów powinno jednakulegać zmianom. Musisz wystrzegać się zarówno arogancji jak i fałszywej skromności jeślichodzi o wiedzęna temat tego, czego naprawdę chce klient. Programiści są wyszkoleni, aby projektować i tworzyć. Analitycy rynku są wyszkoleni by określać, czego chcą ludzie. Harmonijne współdziałanie tych dwóch rodzajów osób bądź dwóch sposobów myślenia u tej samej osoby daje największą szansę na sformułowanie poprawnej wizji.
Im więcej czasu spędzisz z użytkownikami, tym lepiej będziesz mógł zrozumieć cozapewnisukces. Powinieneś sprawdzać swoje pomysły pod kątem ich wymagańtak intensywnie, jak to możliwe. Jeśli tylko możesz, powinieneś nawet spożywać z użytkownikami posiłki.
Guy Kawasaki[Rules] podkreśla znaczenie jakie oprócz słuchania użytkowników ma obserwacja ich zachowań.
Uważam, że kontrahenci i konsultanci mają często ogromny problem ze sprawieniem, by ich klienci mieli jasność co do swoich oczekiwań. Jeśli chcesz być konsultantem, sugeruję, żebyś w takim samym stopniu wybierał klientów w oparciu o jasność ich umysłu jak i o zawartość ich portfela.
Jak uzyskać awans
Aby awansować i otrzymać daną rolę, trzeba tę rolę najpierw odegrać.
Aby awansować na dane stanowisko, dowiedz się,jakie są związane z nim obowiązki i podejmij się ich.
Aby otrzymać podwyżkę, negocjuj będąc wyposażonym w informacje.
Jeśli masz poczucie, że od dawna należy ci się awans, porozmawiaj o tym z szefem. Zapytaj go otwarcie o warunki, jakie musisz spełnić by awansowaći spróbuj je spełnić. Brzmi to banalnie, ale często nasze wyobrażenie o stawianych nam wymaganiach znacząco różnisię od percepcjiszefa. W ten sposób przyciśniesz nieco swojego przełożonego.
Większość programistów prawdopodobnie ma pod pewnymi względamiprzesadne poczucie swoich względnych zdolności– w końcu nie możemy wszyscy należeć do grona najlepszych 10%. Widziałem jednak niektóre osoby, które były wyraźnie niedoceniane. Nie można oczekiwać, że ocena każdego programisty zawsze idealnie pokrywa się z rzeczywistością. Uważam jednak, że ludzie są z regułydosyćuczciwi, z jednym zastrzeżeniem: nie możesz kogoś docenić bez wglądu w jegopracę. Czasem, z powodu zbiegu okoliczności lub osobistych nawyków, programistamoże nie zostać dostatecznie dostrzeżony. Praca z domu lub dzielący daną osobę geograficzny dystans od zespołu i szefa sprawia, że jest to szczególnie trudne.
Służenie zespołowi
Jak rozwijać talent
Nietzsche przesadził mówiąc:
Co mnie nie zabije, to mnie wzmocni.
Twoim największym zobowiązaniem jest to wobec zespołu. Powinieneś dobrze znać wszystkich jego członków. Powinieneś wiele od nich wymagać, ale nie obciążać nadmiernie. Zazwyczaj dobrze jest wytłumaczyćzespołowiw jaki sposób zmuszasz ich do zwiększonego wysiłku. Jeśli w to wejdą, będą zmotywowani. Przy każdym projekcie, lub przy co drugim projekcie, spróbuj wymagać od nich zarówno w sposób, jaki sami sugerują, i w sposób, jaki ty uważasz za dobry dla nich. Zmuszaj ich do rozwoju nie tyle poprzez większy nakład więcej pracy copoprzez wyposażenie ichw nową umiejętność lub, nawetlepiej, poprzez nadanie im nowej roliw zespole.
Powinieneś pozwalać swoim współpracownikom (ciebie nie wyłączając) ponieść sporadycznie porażkę i wziąć na to poprawkę w harmonogramie. Jeśli nie dochodzi do niepowodzeń, może zabraknąć poczucia uczestniczenia w przygodzie. Jeśli nigdy nie mają miejsca sporadyczne niepowodzenia, to znaczy, że nie starasz się wystarczająco mocno. Jeśli ktoś zawodzi, powinieneś być możliwie łagodny, ale nie traktować go jakby odniósł sukces.
Postaraj się, abykażdy członek zespołu włączył się w pracę i był dobrze zmotywowany. Jeśli któremuś z nich brakuje motywacji, spytaj się go otwarcie o to, czego potrzebuje by tę motywację osiągnąć. Być może nie będziesz w stanie zadowolić wszystkich, ale powinieneś wiedzieć, czego chce każdy członek zespołu.
Nie możesz machnąć ręką na kogoś, kto rozmyślnie nie przyjmuje na siebie ciężaru pracy z powodu niskiego morale lub niezadowolenia i pozwolić mu zaniedbywać obowiązki. Musisz spróbować sprawić, by był zmotywowany i wydajny. Dopóki masz cierpliwość, nie przestawaj działać. Kiedy twoja cierpliwość się wyczerpie, zwolnij go. Nie możesz pozwolić pozostać w zespole komuś, kto pracuje poniżej swoich możliwości, ponieważ nie jest to uczciwe wobec reszty pracowników.
Wyraź publicznie i otwarcie swoje uznanie dla umiejętności doświadczonychczłonkówzespołu. Pochwały powinny być udzielanepublicznie, a krytyka prywatnie.
Oczywiściedoświadczeni członkowie zespołu będą mieli przydzielane trudniejsze zadania niż słabsi programiści. Jest to zupełnie naturalne i nikomu nie będzie to przeszkadzało, o ile wszyscy pracująciężko.
Co dziwne, zarobki nie odzwierciedlają tego, że dobry programista jest wydajniejszy od dziesięciu złych programistów. Wytwarza się w ten sposób dziwna sytuacja. Często faktyczniemożna wykonać pracę szybciej, jeśli słabsi programiści nie będą wchodzić nam w drogę. Postępując w ten sposób, rzeczywiście można dokonać większych postępów, ale tylko na krótką metę. Twoja grupastraciłaby ważne korzyści — szkolenie słabszych programistów, rozpowszechnianie tzw. wiedzy plemiennej oraz zdolność do działania w przypadku utraty doświadczonych członków zespołu. Doświadczona osoba musi być delikatna w tym względzie i rozważyć problem pod każdym kątem.
Możesz często powierzyć bardziej doświadczonym członkom zespołu wymagające, ale wyraźnie określone zadania.
Jak wybrać nad czym pracować
Wybierając aspekt projektu, nad którym będziesz pracować musisz wyważyć własne potrzeby i potrzeby zespołu. Powinieneś robić to, w czym jesteś najlepszy, ale spróbuj znaleźć sposób, aby się wysilać nie poprzez pracowanie więcej, ale poprzez uczenie się nowych umiejętności. Umiejętności przywódcze i komunikacyjne są ważniejsze niż umiejętności techniczne. Jeśli jesteś bardzo doświadczony, weź na siebie najtrudniejsze lub najbardziej ryzykowne zadanie projektu i wykonaj je najwcześniej, jak to tylko możliwe by zminimalizować ryzyko.
Jak uzyskać jak najwięcej od kolegów z zespołu
Aby uzyskać jak najwięcej od swoich współpracowników, rozwijaj ducha zespołu i próbuj sprawić, by każda osoba była zarazem zmobilizowana i osobiście zaangażowana.
W podtrzymywaniu ducha zespołu sprawdzają się oklepane sposoby takie jak ubrania z logo firmy czy przyjęcia, ale nie są tak dobre jak osobisty szacunek. Jeśli wszyscy szanują się nawzajem, nikt nie będzie chciał sprawić nikomu zawodu. Duch zespołu tworzy się wówczas, gdy ludzie poświęcają się na rzecz grupy i w pierwszej kolejności myślą o dobru zespołu, a nie o własnych korzyściach. Jako szef nie możesz wymagać więcej, niż dajesz w tym względzie od siebie.
Jedną z kluczowych kwestii dotyczących kierowania zespołem jest ułatwianie konsensusu i pozyskiwanie akceptacji wszystkich członków zespołu. Czasem musisz więc dopuścić do sytuacji, w której Twoi koledzy będą w błędzie. Jeśli tylko takie posunięcie nie wyrządzizbytniej szkody dla projektu, musisz pozwolić niektórym osobom z zespołu zrobić coś po swojemu, dopuścić konsensus, nawet wtedy jeślijesteś przekonany, że to niesłuszne rozwiązanie. Kiedy zachodzi taka okoliczność, nie wyrażaj swojej zgody, wyraź swoją negatywną opinię i zaakceptuj konsensus.Nie bądź urażony ani nie sprawiaj wrażenia, że zostałeś do tego zmuszony— powiedzpo prostu, że się nie zgadzasz, ale uważasz, że konsensus wśród członków zespołu jest ważniejszy. W rezultacie członkowie zespołu często wycofują się z pierwotnej decyzji.Jeśli tak się stanie, nie nalegaj, by postępowali zgodnie z początkowym planem.
Jeśli znajdzie się osoba, która nie akceptuje konsensusu mimo tego, że omówiłeś problem we wszystkich aspektach, po prostu zaznacz, że to ty musisz podjąć decyzję i ją przedstaw. Jeśli istnieje sposób, aby ocenić, czy twoja decyzja okaże się niesłuszna, lub jeśli zostanie to później wykazane, zmień ją możliwie szybko i doceń osoby, które miały rację.
Zapytaj zespół, zarówno całą grupę jak i każdego z jej członków z osobna, co ich zdaniem może wytworzyć ducha zespołu i pozytywnie wpłynąć na efekty pracy.
Udzielaj pochwał często, ale nie szczodrze. Chwal zwłaszcza tych, którzy się z tobą nie zgadzają, a kiedy zasługują na pochwałę. Chwal publicznie a krytykuj prywatnie, z jednym wyjątkiem: czasem rozwój lub poprawa błędu nie może być chwalona bez przyciągania kłopotliwej uwagi do samego błędu, więc pochwał dotyczących tego typu postępównależy udzielaćna osobności.
Jak dzielić problemy na mniejsze części
Podjęcie się projektu oprogramowania i wydzielenie zadań dla konkretnych osóbto niezła zabawa i należy to zrobić jak najwcześniej. Czasami menedżerowie myślą, że oszacowanie może być dokonane bez uwzględnienia osób, które mają wykonać pracę. Jest to niemożliwe, ponieważ wydajność poszczególnych osób bardzo się różni. Nawet ten, kto ma konkretną wiedzę o komponencie także stale się zmienia i może mieć wpływ na wydajność różny orząd wielkości.
Tak jak kompozytor uwzględnia brzmienie instrumentu, który zagra, czy takjak trener zespołu sportowego bierze pod uwagę zalety każdego zawodnika, doświadczony szef zespołu pracowników nie jest zazwyczaj w stanie oddzielić podziału projektu na zadania od członków zespołu, którym zostaną one przypisane. Częściowo z tego względuwysoce efektywnezespoły nie powinny być rozdzielane.
Istnieje pewne niebezpieczeństwo polegające na tym, że pracownicymogą ulec znużeniu podczasrozwijania swoichmocnych stron, a jednocześnienie będą pracować nad słabościami albo uczyć się nowych umiejętności. Specjalizacja jest jednak bardzo użytecznym narzędziem zwiększania wydajności, o ilenie jest nadużywana.
Jak radzić sobie z nudnymi zadaniami
Czasami nie da się uniknąć nudnych zadań, które mają krytyczne znaczenie dla powodzenia przedsiębiorstwa lub projektu. Zadania te mogą mieć naprawdę negatywny wpływ namorale tych, którzy muszą je wykonać. Najlepszą techniką radzenia sobie w takich przypadkach jest przywołanie lub propagowanie „cnoty lenistwa programisty” zaproponowanej przez Larry`ego Walla. Spróbuj sprawić, żeby komputer wykonał danezadanie za ciebie lub pomógłw nimkolegom. Poświęcenie tygodnia na opracowanie programu, który wykona za nas zadaniemogące zająć nam samym tydzień ma tę wielką zaletę, że jest bardziej pouczające, a czasem bardziej powtarzalne.
Jeśli wszystko inne zawiedzie, przeproś tych, którzy muszą wykonać nudne zadanie, ale pod żadnym pozorem nie pozwól im robić tego samym. Przypisz pracę przynajmniej dwuosobowemu zespołowi i dbajo zdrowe zasadywspółpracy, aby zadanie zostało zrealizowane.
Jak pozyskać wsparcie dla projektu
Aby uzyskać wsparcie dla projektu, stwórz i przekaż wizję, która stanowi prawdziwą wartość dla organizacji pojmowanej jako całość. Spróbuj umożliwić uczestnictwo w tworzeniu wizji innym. Dzięki temu będą skłonni cię poprzeć, a Ty skorzystasz z ich pomysłów. Indywidualnie pozyskuj kluczowe osoby popierające twój projekt. Kiedy tylko to możliwe pokazujswoje sugestie, a nie tylko je omawiaj. Jeśli jest ku temu sposobność, skonstruuj prototyp lub model demonstrujący twoje pomysły. Prototyp mazawszewielkie możliwości, ale w dziedzinie oprogramowania szczególnie przeważa nadjakimkolwiek opisem na papierze.
Jak rozwijać system
Nasiono drzewa zawiera ideę dojrzałego organizmu, ale nie realizuje w pełni jego formy i potencjału. Embrion rozwija się. Staje się większy. Przypomina bardziej dojrzały organizm i posiada więcej zastosowań. W końcu rodzi owoce. Później umiera, a jego ciałem żywią się inne organizmy.
Mamy ten luksus, że możemy w ten sposób traktować oprogramowanie. Inaczej jest w przypadku mostu: nigdy nie istnieje dziecięca wersja mostu, jest tylko most niedokończony. Mosty są dużo prostsze niż oprogramowanie.
Warto myśleć ooprogramowaniujako o dojrzewającym organizmie, ponieważ dzięki temu możemy dokonać użytecznych postępów zanim uzyskamy idealny obraz mentalny. Możemy pozyskaćopinie użytkowników i z ich pomocąskorygować rozwój. Przycinanie słabych konarów jest rzeczą zdrową.
Programista musi zaprojektować skończony system, który może zostać dostarczony i być używany. Ale zaawansowany programista musi zrobić znacznie więcej. Musisz zaprojektować ścieżkę wzrostu, której kresem jest ukończony produkt. Twoim obowiązkiem jest wziąć zarodek pomysłu i zbudować ścieżkę, która prowadzi możliwie łagodnie do użytecznego produktu.
Aby tego dokonać, musisz wizualizować rezultat końcowy i przekazać go tak, aby wywołać w zespole inżynierów entuzjazm. Musisz im jednak zakomunikować również ścieżkę, która wiedzie od miejsca, w którym się znajdują, do miejsca, w którym chcą się znaleźć bez gwałtownych przeskoków. Drzewo musi być zachowane przy życiu przez cały czas, nie może być martwe w jednym momencie, a wskrzeszone w innym.
Takie podejście obrazuje rozwój w kształcie spirali. Kamienie milowe projektu, które nie są od siebie zbytnio oddalone wykorzystuje się dooznaczenia postępu wzdłuż ścieżki. W najbardziejkonkurencyjnychśrodowiskach biznesowych najlepiej jest, jeśli kamienie milowe mogą zostać opublikowane i zarabiać na siebie tak szybko jak to możliwe, nawet jeśli są odległe od dobrze zaprojektowanego rezultatu końcowego. Jednym z obowiązków programisty jest mądre zrównoważenieobecnychowoców pracy w stosunku do przyszłych wyników poprzez wybór ścieżki wzrostu wyrażonej w kamieniach milowych.
Zaawansowany programista ma potrójne obowiązki rozwijania oprogramowania, zespołów oraz osób.
Czytelnik, Rob Hafernik, przysłał ten komentarz na tematniniejszejczęści poradnika, więc nie pozostaje mi nic innego jak zacytować go w pełni:
Uważam, że niedostatecznie podkreślasz znaczenie mierzenia postępów. Nie chodzi tylko systemy, ale algorytmy, interfejsy użytkownika, modele danych itd. Rzeczą absolutnie podstawową podczas pracy nad dużym systemem jest możliwość obserwacji mierzalnego postępu względem pośrednich celów. Nie ma nic gorszego od wyjątkowego przerażenia poskończeniupracy, gdy uświadamiamy sobie, że cały utworzony system nie będzie działał (patrz ostatniefiaskosystemu informacji o wyborach). Powiem więcej, to prawo natury: żaden duży, złożony system nie może być zaimplementowany od zera, może być jedynie rozwijany z prostego systemu do systemu złożonego poprzez serię zamierzonych kroków
Jedyna odpowiedź może brzmieć: Niech się stanie światłość!
Jak się dobrze komunikować
Aby dobrze się komunikować, musisz mieć świadomość jak bardzo jest to trudne. To umiejętność cenna sama w sobie. Tym, co czyni ją jeszcze trudniejszą, jest to, że osoby, z którymi się komunikujesz są niedoskonałe. Nie wysilają się, aby cię zrozumieć. Kiepsko mówią i piszą. Są często przepracowani lub znudzeni i, w najlepszym przypadku,nieco bardziej skupieni na własnej pracy niż na poważniejszych problemach, z którymi ty się borykasz. Jedną z zalet brania udziału w zajęciachi ćwiczenia pisania, publicznych wystąpień i słuchania jest to, że jeśli staniesz się w tym dobry, możesz łatwiej dostrzegać przyczyny trudności i sposoby na zaradzenie im.
Programista jest istotą społeczną, której przetrwanie zależy od komunikacji ze swoim zespołem. Zaawansowany programista jest istotą społeczną, której satysfakcja zależy od komunikacji z ludźmi spoza zespołu.
Programista przekształca chaos w porządek. Jednym z interesujących sposobów by to zrobić jest zainicjowanie jakiejś propozycji poza zespołem. Można sporządzić wersję roboczą, przygotować białą księgę albo po prostu omówić daną propozycję. Bycie na czele ma ogromną zaletę określania warunków debaty. Naraża cię to również na krytycyzm, a co gorszana odrzucenie i zignorowanie. Zaawansowany programista musi być gotowy to zaakceptować, ponieważ ma jedyną w swoim rodzaju moc, a przez to nadzwyczajną odpowiedzialność. Przedsiębiorcy, którzy nie są programistami, potrzebują ich, aby zapewnić sobie w jakiś sposób przywództwo. Programiści stanowią część pomostu między pomysłami a rzeczywistością i opierają się na tej rzeczywistości.
Nie opanowałem dobrze komunikacji, ale to, co próbuję tutaj przekazać to w mojej ocenie podejście czterostronne: po uporządkowaniu pomysłów i przygotowaniu się w pełni próbuję komunikować się z ludźmiwerbalnie, dostarczyć im białą księgę (na papierze jak i elektronicznie), pokazać demonstrację, a potem cierpliwie powtarzam ten proces. Sądzę, że często nie jesteśmy dostatecznie cierpliwi, jeśli chodzi o ten rodzaj trudnej komunikacji. Nie powinieneś się zniechęcać, jeśli twoje pomysły nie są natychmiast akceptowane. Jeśli poświęciłeś się tym przygotowaniom, nikt nie będzie myślał o tobie źle z tego powodu.
Jak mówić ludziom to, czego nie chcą usłyszeć
Będziesz często musiał mówić ludziom coś, przez co poczują się niewygodnie. Pamiętaj, że robisz to z określonego powodu. Nawet jeśli nic nie można zrobić z danym problemem, oznajmij to tak wcześnie, jak to tylko możliwe, żeby twoi współpracownicy byli właściwie poinformowani.
Najlepszym sposobem, aby powiedzieć komuś o problemie, jest zaoferowanie jednocześnie rozwiązania. Innym dobrym sposobem jest zaapelowanie do członków zespołuo pomoc w rozwiązaniu problemu. Jeśli istnieje ryzyko, że ci nie uwierzą, powinieneś zgromadzić informacje, które potwierdzą twoje zapewnienia.
Jedną z najbardziej nieprzyjemnych i powszechnych rzeczy, jakie będziesz musiał mówić jest: „Harmonogram będzie musiał ulec przesunięciu”. Sumienny programista nie znosi tego mówić, ale musi to powiedzieć tak wcześnie, jak to tylko możliwe. Nie ma nic gorszego niż odwlekanie działań, kiedy kamień milowy ulega przesunięciu, nawet jeśli jedynym działaniem może być poinformowanie o tym wszystkichzainteresowanych. Jeśli już dochodzi do takiej sytuacji, lepiej jest zrobić to jako zespół, przynajmniej w duchu, jeśli nie fizycznie. Będziesz chciał uzyskać wkład zespołu na temat tego,w jakim punkcie jesteś i co możesz z tym zrobić, a zespół będzie musiał stawić czoła konsekwencjom razem z tobą.
Jak rozprawić się z mitami na temat zarządzania
Słowo mit oznacza fikcję. Ale ma też głębsze konotacje. Oznacza również opowieść o znaczeniu religijnym, która tłumaczy wszechświat i związek ludzkości z nim. Menedżerowie często zapominają czego nauczyli się jako programiści i wierzą w określone mity. Niegrzecznąi skazanąna niepowodzenie byłabypróbaprzekonaniaichco do nieprawdziwości tych mitów, podobnie jak próba rozwiania złudzeń żarliwie religijnej osoby co do jej przekonań. Z tego powoduza mity powinieneś uznać poniższe przekonania:
- Im więcej dokumentacji, tym lepiej. (menedżerowie jej oczekują, ale nie mają zamiaru przeznaczyć ci na nią więcej czasu)
- Programiści mogą być uznani za równych sobie. (programiści różnią się o rzędy wielkości)
- Aby przyspieszyć opóźniony projektmożna przeznaczyć na niego zasoby. (koszt komunikacji z nowymi osobami jest niemal zawsze większy niż korzyści)
- Możliwe jestwiarygodne oszacowanie rozwoju oprogramowania. (nie jest to nawet teoretycznie możliwe)
- Wydajność programistów może być mierzona w kategoriach prostej miary, tak jak linie kodu. (jeśli zwięzłość to moc, linie kodu sązłe, a nie dobre)
Jeśli masz okazję, możesz spróbować wyjaśnić powyższe mity.Nie czuj się jednak źle, jeśli się to nie powiedzie i nie czyń szkody dla swojej reputacji konfrontując się z tymi mitami w sposób agresywny. Każdy z tych mitów umacnia menedżera w przekonaniu, że sam ma jakąś rzeczywistą kontrolę nad tym, co się dzieje. Prawda jest taka, że menedżerowie ułatwiają pracę, jeśli są dobrzy, i przeszkadzają, jeśli są słabi.
Jak radzić sobie z organizacyjnym chaosem
Często zdarzają się krótkie okresy ogromnego chaosu organizacyjnego, takie jak redukcje zatrudnienia, wykupy akcji, pierwsze oferty publiczne, zwolnienia, nowe zatrudnienia itp. Są one niepokojące dla wszystkich, ale być może mniej niepokojące dla programisty, którego samoocena jest oparta bardziej na umiejętnościach aniżeli na stanowisku. Chaos organizacyjny to świetna okazja dla programistów by wykorzystać swoje moce magiczne. Zachowałem to sobie na koniec, ponieważ jest to najskrytszysekret naszej grupy zawodowej. Jeśli nie jesteś programistą, odłóż ten tekst natychmiast.
Inżynierowie mają moc, by tworzyć i podtrzymywać.
Nieinżynierowie mogą rozkazywać wszystkim wokół, ale w typowej firmie zajmującej się oprogramowaniem nie są w stanie nic tworzyć i podtrzymywać nic bez pomocy inżynierów, podobnie jak inżynierowie zazwyczaj nie potrafią sprzedać produktu lub efektywnie zarządzać przedsiębiorstwem. Ta umiejętność jest dowodem przeciwko prawie wszystkim problemom związanym z chwilowym zamętem organizacyjnym. Jeśli ją posiadasz, powinieneś zignorować chaos zupełnie i kontynuować pracę, tak jakby nic się nie działo. Możesz, rzecz jasna, zostać zwolniony, ale jeśli do tego dojdzie, prawdopodobnie dostaniesznową pracę dzięki swojej magicznej mocy. Co bardziej powszechne, jakaś zestresowana osoba, która nie posiada magicznych mocy, przyjdzie do twojego boksu i każe ci zrobić coś głupiego. Jeśli naprawdę jesteś pewien, że jest to głupie, najlepiej jest się uśmiechnąć się i kiwać głową do czasu, aż osoba sobie pójdzie i robić dalej to, co twoim zdaniem jest najlepsze dla przedsiębiorstwa.
Jeśli jesteś liderem zespołu, powiedz swoim współpracownikom, by robili to samo i ignorowali to, co mówią im inni. Takisposób postępowania jest dla ciebie osobiście najlepszy, jak również dla przedsiębiorstwa i projektu.
Słowniczek
Niniejszy słowniczek zawiera terminy użyte w niniejszymeseju. Niekoniecznie posiadają one ustandaryzowane znaczenie dla innych osób. Eric S. Raymond skompilował obszerny i pouczający słowniczek[HackerDict], który można, co zaskakujące, z przyjemnością czytać od deski do deski kiedy już doceni się choćby jego część.
- n.n.
- Slangowe określenie nieznanych niewiadomych. Problemy, które nie mogą być obecnie określone oraz które zabierają czas potrzebny dla projektu i rujnują harmonogram.
- szef
- Osoba lub jednostka, która powierza ci zadania. W niektórych przypadkach mogą być to ogólnie odbiorcy.
- printlining/wyrażenia wyświetlające dane
- Tymczasowe umieszczanie w programie wyrażeń, które wyświetlają informację na temat wykonania programu dla celów debugowania.
- prowadzenie dziennika
- Praktyka polegająca na pisaniu programu w taki sposób, aby tworzył dziennik zawierający konfigurowalne dane wyjściowe opisujące jego wykonanie.
- dziel i zwyciężaj
- Technika projektowania zstępującego i, co ważne, debugowania polegająca na podziale problemu lub tajemnicy na stopniowomniejsze problemy lub tajemnice.
- vaporware
- Iluzoryczne i często zwodnicze obietnice co do oprogramowania które jeszcze nie jest na sprzedaż i, przeważnie, nigdy nie osiągnie konkretnej formy.
- szef
- Osoba, która wyznacza ci zadania. W niektórych przypadkach twoim szefem jest użytkownik.
- grupa
- Ludzie z którymi łączy cię lojalność i wspólny cel.
- nisko zawieszony owoc
- Duża poprawa małym kosztem.
- przedsiębiorca
- Inicjator projektów.
- śmieci
- Obiekty, które nie są już potrzebne, a które zajmują pamięć.
- firma
- Zorganizowana grupa osób, których celem jest zarabianie pieniędzy.
- przedsiębiorstwo
- Zorganizowana grupa osób, których celem jest zarabianie pieniędzy.
- grupa
- Osoby, z którymi łączy cię kulturowe podobieństwo i lojalność.
- niedostrzeganie danych
- Efekt polegający na tym, że nie jesteś w stanie znaleźć informacji, których potrzebujesz, ponieważ jest ona ukryta pośród innych, mniej istotnych danych.
- czas zegarowy
- Rzeczywisty czas mierzony według zegara, w przeciwieństwie do czasu procesora.
- wąskie gardło
- Najważniejsze ograniczenie wydajności systemu. Ograniczenie, które obniża wydajność.
- dane nadrzędne
- Unikalna informacja, z której pochodzą wszystkie kopie zapisane w pamięci podręcznej i która służy za oficjalną definicję tych danych.
- sterta alokowana
- Pamięć może być uznana za stertę alokowaną wtedy, gdy mechanizm jej zwalniania jest skomplikowany.
- śmieci
- Pamięć alokowana, która nie ma już użytecznego znaczenia.
- odśmiecacz
- System służący do odzyskiwania śmieci.
- wyciek pamięci
- Niechciany zbiór referencji do obiektów, który uniemożliwia odśmiecanie (bądźbłąd w odśmiecaczu lub systemie zarządzania pamięcią!), który powoduje, że program stopniowo zwiększa swoje zapotrzebowanie na pamięć wraz z upływem czasu.
- programowanie ekstremalne
- Styl programowania uwypuklający komunikację z klientem i zautomatyzowane testowanie.
- zderzenie się ze ścianą
- użycie określonych zasobów, w wyniku czego następuje gwałtowny, a nie stopniowy, spadek wydajności.
- programowanie oparte na spekulacjach
- Wytworzenie właściwości, zanim będzie wiadomo, że jest ona użyteczna.
- ukrywanie informacji
- Zasada projektowania, której celem jest zachowanie komponentów niezależnymi i oddzielonymi poprzez użycie interfejsów, które ujawniają jak najmniej informacji.
- programowanie obiektowe
- Styl programowania, który kładzie nacisk na zarządzanie stanem obiektów.
- języki komunikacyjne
- Języki zaprojektowany przede wszystkim dla celów standaryzacji a nie wykonania.
- prostokąty i strzałki
- Luźny, nieformalny styl tworzenia diagramów składających się z prostokątów i strzałek, które je łączą, by pokazać wzajemne relacje. Przeciwieństwo formalnych metodologii tworzenia diagramów, takich jak UML.
- lingua franca
- Język tak popularny, będący de facto standardem dla danej dziedziny, jak niegdyś język francuski dla międzynarodowej dyplomacji.
- kup lub zbuduj
- Określenieopisujące wybór pomiędzy wydawaniem pieniędzy na oprogramowanie lub napisaniem go samemu.
- zwykła praca
- Praca, która nie wymaga wiele kreatywności i wiąże się z małym ryzykiem. Może być łatwo oszacowana.
- notacja programowania
- Synonim języka programowania, który podkreśla jego matematyczną naturę i jego stosunkową prostotę w porównaniu z językiem naturalnym.
- dokument roboczy (ang. strawmanproposal, człowiek ze słomy)
- Dokument, który ma stanowić punkt wyjścia do technicznej dyskusji. Może prowadzić do stickmanaczłowieczka z kresek), tinmana (człowieka z puszek), woodmana (człowieka z drewna), ironmana (człowieka z żelaza) itp.
- biała księga
- Pouczający dokument, który często ma na celu wyjaśnić lub sprzedać produkt albo pomysł skierowany do odbiorcy innego niż programista tegoż produktu lub pomysłu.
Bibliografia/ Strony internetowe
Książki
[Rules00] Guy Kawasaki, Michelle Moreno i Gary Kawasaki. 2000. HarperBusiness. Rules for Revolutionaries: The CapitalistManifesto for Creating and Marketing New Products and Services.
[RDev96] SteveMcConnell. 1996. Microsoft Press. Redmond, Wash. Rapid Development: Taming Wild Software Schedules.
[CodeC93] SteveMcConnell. 1993. Microsoft Press. Redmond, Wash. Code Complete. Polskie wydanie: Steve McConnell. 2010. Helion. Kod doskonały. Jak tworzyć oprogramowanie pozbawione błędów. Wydanie II.
[XP99] Kent Beck. 1999. 0201616416. Addison-Wesley. Extreme Programming Explained: EmbraceChange.
[PlanXP00] Kent Beck and Martin Fowler. 2000. 0201710919. Addison-Wesley. Planning Extreme Programming.
[Prag99] AndrewHunt, David Thomas iWard Cunningham. 1999. 020161622X. Addison-Wesley. The Pragmatic Programmer: From Journeyman to Master. Polskie wydanie: Helion. 2011. Pragmatyczny programista. Od czeladnika do mistrza.
[Stronger] Friedrich Nietzsche. 1889. Twilight of the Idols, "Maxims and Arrows", ustęp 8.
Strony internetowe:
[PGSite] Paul Graham. 2002. Artykuły na stronie autora: http://www.paulgraham.com/articles.html. Wszystkie, a zwłaszcza „Beating the Averages”.
[Hacker] Eric S. Raymond. 2003. How to Become a Hacker. http://www.catb.org/~esr/faqs/hacker-howto.html.
[HackDict] Eric S. Raymond. 2003. The New Hacker Dictionary. http://catb.org/esr/jargon/jargon.html.
[ExpCS] Edsger W. Dijkstra. 1986. How Experimentalis Computing Science?. http://www.cs.utexas.edu/users/EWD/ewd09xx/EWD988a.PDF.
[Knife] Edsger W. Dijkstra. 1984. On a Cultural Gap. http://www.cs.utexas.edu/users/EWD/ewd09xx/EWD913.PDF.
Wersja oryginalna
Praca nad oryginalną wersją niniejszego dokumentu została rozpoczęta przez Roberta L. Reada w roku 2000 i została opublikowana elektronicznie na Samizdat Press(http://Samizdat.mines.edu) w roku 2002. Jest dedykowana programistom z Hire.com.
Po tym, jak o artykule wspomniano na portalu Slashdot w roku 2003 około 75 osób przysłało mi e-maile z sugestiami i erratą. Cenię je sobie wszystkie. Uwagi często się powtarzały, ale poniższe osoby przedstawiły co ważniejsze sugestie lub jako pierwsze znalazły błędy, które poprawiłem: Morgan McGuire, David Mason, Tom Moertel, Ninja Programmer (145252) na Slashdot, Ben Vierck, Rob Hafernik, Mark Howe, PieterPareit, Brian Grayson, Zed A. Shaw, Steve Benz, MaksimIoffe, Andrew Wu, David Jeschke i Tom Corcoran.
Wreszcie chciałbym podziękować Christinie Vallery, którejredakcja i korekta znacząco poprawiły drugi projekt artykułu, oraz Wayne`owi Allenowi, który zachęcił mnie, abym rozpoczął ten projekt.
Biografia autora
Robert L. Read mieszka w Austin w Texasie z żoną i dwójką dzieci. Obecnie jest głównym inżynierem na Hire.com, gdzie pracuje od czterech lat. Wcześniej założył firmę 4R Technology, która stworzyła narzędzie kontroli jakości analizy zeskanowanych obrazów dla przemysłu papierniczego.
Read uzyskał doktorat na Uniwersytecie Stanowym Teksasu w Austin w 1995 roku z dziedziny informatyki związanej z teorią baz danych. W 1987 otrzymał tytuł licencjata z informatyki na Uniwersytecie Rice. Jest zawodowym programistą od 16. roku życia.
Niewielki błąd ——————-/
JAK ROZPRAWIĆ SIĘ Z MITAMI NA TEMATZARZĄDZANIA