Elegancja rozwiązań
Pracując w branży IT, bardzo łatwo skupić się na dużych, złożonych rozwiązaniach. Wydaje się, że właśnie tam tkwią dobre rozwiązania – duże systemy, mnóstwo oprogramowania, wszystkie najnowsze gadżety. To, co robimy, jest ekscytujące i bardzo łatwo dać się ponieść temu momentum. Realizacja wymagających, dużych projektów dostarcza satysfakcji. Słuchanie o tym, co robią inni specjaliści IT, jak inne firmy rozwiązują problemy, i rozmowy z dostawcami oferującymi rozbudowane systemy – wszystko to potęguje emocje. Bardzo łatwo zatracić poczucie skali i celu, a widok skomplikowanych, przesadzonych rozwiązań prostych problemów jest tak powszechny, że można odnieść wrażenie, iż tak po prostu działa IT.
Ale nie musi tak być. Złożoność jest wrogiem zarówno niezawodności, jak i bezpieczeństwa. Niepotrzebnie skomplikowane rozwiązania zwiększają koszty – zarówno zakupu, jak i wdrożenia oraz utrzymania – a jednocześnie są generalnie wolniejsze, bardziej podatne na awarie i posiadają rozbudowaną powierzchnię ataku, którą trudniej zrozumieć i chronić. Proste, a właściwiej mówiąc eleganckie rozwiązania to najlepsze podejście. Nie oznacza to, że wszystkie projekty będą proste – wcale nie. Złożone projekty są często niezbędne. IT to branża, która na pewno nie cierpi na brak złożoności. W rzeczywistości powszechnie uważa się, że wytwarzanie oprogramowania może być najbardziej skomplikowanym z ludzkich przedsięwzięć, przynajmniej spośród tych realizowanych na jakąkolwiek skalę. Typowa instalacja IT obejmuje miliony linii kodu, setki lub tysiące protokołów, dużą liczbę powiązanych ze sobą systemów, warstwy unikalnych konfiguracji oprogramowania, więcej ustawień niż jakikolwiek zespół jest w stanie ogarnąć – a do tego dochodzi złożoność wynikająca z setek, tysięcy lub setek tysięcy nieprzewidywalnych, nieracjonalnych ludzi próbujących korzystać z tych systemów, każdy na swój własny sposób. IT jest, bez wątpienia, złożone.
Ważne jest to, by rozpoznać, że IT jest złożone i że nie można tego całkowicie uniknąć – ale skupić się na projektowaniu i inżynierii rozwiązań możliwie prostych, możliwie eleganckich. Taka idea projektowania wywodzi się – przynajmniej w moim odczuciu – z inżynierii oprogramowania, gdzie złożony kod jest traktowany jako błąd, a prosty, piękny kod, który jest łatwy do czytania i rozumienia, uważany jest za sukces. Jedną z najwyższych pochwał, jakie można przyznać programistce, jest uznanie jej kodu za elegancki. Jakże trafne jest przypisywane Blaise’owi Pascalowi – temu samemu, od którego nazwano jeden z najpopularniejszych języków programowania lat 70. i 80. – słynne powiedzenie (luźno przetłumaczone z francuskiego): “Przepraszam, że napisałem tak długi list, ale nie miałem czasu napisać krótszego.”
Często znacznie łatwiej jest zaprojektować skomplikowane, zawiłe rozwiązania niż ustalić, jakie proste podejście wystarczyłoby. Niezależnie od tego, czy się śpieszymy, czy nie wiemy, od czego zacząć analizę, elegancja jest zawsze wyzwaniem. Branżowe momentum sprzyja trudniejszej ścieżce. W interesie dostawców leży sprzedaż większej ilości sprzętu – nie tylko po to, by sfinalizować początkową transakcję, ale dlatego, że wiedzą, iż więcej sprzętu oznacza więcej przychodów z wsparcia technicznego. Jeśli sprzedaje się wystarczająco dużo nowego, złożonego sprzętu, koszty wsparcia przestają rosnąć liniowo i zaczynają rosnąć geometrycznie, ponieważ dodatkowe wsparcie jest potrzebne nie tylko dla samego sprzętu czy oprogramowania, ale też dla konfiguracji i obsługi interakcji między systemami lub dodatkowych dostosowań. Finansowe bodźce sprzyjające złożoności są ogromne i nie kończą się na dostawcach. Specjaliści IT zyskują duże poczucie bezpieczeństwa zawodowego – lub jego iluzję – zarządzając rozległymi zasobami sprzętu i oprogramowania trudnymi do płynnego przekazania innemu specjaliście.
Często złożoność jest tak zakładana z góry, tak oczekiwana, że proces wyboru rozwiązania rozpoczyna się od dużej złożoności jako pewnika, bez jakiegokolwiek rozważenia możliwości, że mniej złożone rozwiązanie mogłoby wystarczyć, a nawet okazać się lepsze – niezależnie od kwestii złożoności i kosztów. Złożoność bywa nawet całkowicie utożsamiana z pewnymi koncepcjami do tego stopnia, że spotkałem się z autentycznym niedowierzaniem na myśl, iż proste rozwiązanie mogłoby być lepsze pod względem ceny, wydajności i niezawodności niż skomplikowane.
Retoryka jest łatwa, ale jaki jest przykład z rzeczywistości? Najlepsze przykłady, które widzę dziś, dotyczą głównie wirtualizacji – czy to w kontekście storage’u, warstwy zarządzania chmurą, oprogramowania, czy po prostu samej wirtualizacji. Bardzo często obserwuję, że rozmowa dotycząca jedynie wirtualizacji dla jednej osoby natychmiast kojarzy się z koniecznością posiadania sieciowego, współdzielonego storage’u blokowego, drogiego oprogramowania do zarządzania wirtualizacją, wielu redundantnych węzłów wirtualizacyjnych i złożonego oprogramowania do wysokiej dostępności – a żaden z tych elementów nie jest nieodłączny dla wirtualizacji i większość z nich rzadko służy wsparciu lub rzeczywistemu interesowi firmy, dla której zostanie wdrożona. Zamiast wychodzić od wymagań biznesowych, koncepcje te wynikają głównie z technologicznych uprzedzeń. Łatwo jest wskazać na złożoność i sprawiać wrażenie, że rozwiązuje się problem – złożoność daje poczucie komfortu. Filtrując wiele argumentów, usłyszy się: “Jak to może nie działać, skoro jest złożone?” Złożoność tworzy iluzję kompletności, rozwiązania problemu, ale może to często ukrywać fakt, że rozwiązanie nie jest faktycznie kompletne ani nawet funkcjonalne – a stopień złożoności utrudnia to dostrzeżenie. Nasz umysł nie jest wówczas skłonny do zaakceptowania, że prostsze podejście może być bardziej kompletne i rozwiązywać problem, gdy złożone nie rozwiązuje, bo wydaje się to tak sprzeczne z intuicją.
Dobrym przykładem jest to, że uciekamy się do omawiania redundancji zamiast niezawodności. Niezawodność jest trudna do zmierzenia, redundancja jest prosta do skwantyfikowania. Cegła jest wysoce niezawodna, nawet jako element pojedynczy. Cegła nie potrzebuje redundancji, by być stabilna i wytrzymała. Jej projekt jest prosty. Można zbudować konstrukcję nośną z wielu redundantnych patyczków, która nie będzie w przybliżeniu tak niezawodna jak pojedyncza cegła. Jeśli mówisz o niezawodności – szansie, że konstrukcja nie zawiedzie – jasne jest, że cegła jest lepszym wyborem niż kilka patyczków. Ale jeśli powiesz “ale nie ma redundancji, cegła może się złamać i nie ma nic, co ją zastąpi”, brzmi to absurdalnie. Jednak mówiąc o komputerach i systemach komputerowych, spotykamy systemy tak złożone, że rzadko ktoś dostrzega, czy ma do czynienia z cegłą czy z patyczkiem – i ponieważ nie można określić niezawodności, która ma znaczenie, skupiają się na łatwej do skwantyfikowania redundancji, która go nie ma. Cały system jest zbyt złożony, ale szukanie prostego rozwiązania, które bezpośrednio adresuje sedno problemu, może redukować złożoność i zapewnić nam znacznie lepszą odpowiedź w ostateczności.
Można to zaobserwować nawet w RAID. Lustrzany RAID jest prosty – tylko jeden dysk lub zestaw dysków będący dokładną kopią innego zestawu. To takie proste. Parzystościowy RAID jest złożony – z obliczeniami na zmiennym pasku rozłożonym na wielu urządzeniach, które muszą być kodowane przy zapisie i dekodowane w przypadku awarii urządzenia. Lustrzany RAID nie ma tej złożoności i rozwiązuje problem niezawodności dysków poprzez proste, eleganckie operacje kopiowania, które są wysoce niezawodne i doskonale rozumiane. Parzystościowy RAID jest niepotrzebnie złożony, co czyni go kruchym. A jednocześnie, podważając własną zdolność do rozwiązania problemu, dla którego został zaprojektowany, jednocześnie wydaje się bardziej niezawodny – z żadnego innego powodu niż własna złożoność. Ludzki umysł natychmiast przeskakuje do “to jest złożone, więc jest bardziej zaawansowane, więc jest bardziej niezawodne” – ale żadna z tych implikacji nie jest logiczna. Złożoność nie sugeruje, że jest bardziej zaawansowane, a bycie zaawansowanym nie sugeruje, że jest niezawodne – ale sam ludzki umysł jest złożony i łatwo go wprowadzić w błąd.
Nie ma prostej odpowiedzi na znalezienie prostoty. Wiedza, że złożoność jest zła z natury, ale czasem nieunikniona, uczy nas czujności – jednak nie uczy nas, kiedy podejrzewać nadmierną złożoność. Musimy być czujni, zawsze dążąc do sprawdzenia, czy istnieje bardziej elegantna odpowiedź, i nie akceptować złożoności jako właściwej odpowiedzi tylko dlatego, że jest złożona. Musimy kwestionować proponowane rozwiązania i kwestionować samych siebie. “Czy to rozwiązanie jest naprawdę tak proste, jak powinno być?” “Czy ta złożoność jest konieczna?” “Czy to wymaga złożoności, którą zakładałem?”
W większości rekomendacji dotyczących projektowania systemów, jakie wydaję, pierwszym technicznym krokiem, który normalnie podejmuję – po zapytaniu o potrzebę biznesową, którą należy zaspokoić – jest zakwestionowanie złożoności. Jeśli złożoność nie może być uzasadniona, prawdopodobnie jest zbędna i aktywnie przeczy celowi, dla którego została wybrana.
“Czy naprawdę konieczne jest podzielenie tych dysków na wiele osobnych macierzy? Jeśli tak, jakie jest techniczne uzasadnienie?”
“Czy współdzielony storage jest naprawdę niezbędny do zadania, dla którego go proponujesz?”
“Czy biznes naprawdę uzasadnia zastosowanie rozproszonych technologii wysokiej dostępności?”
“Dlaczego zastępujemy prosty system, który był wystarczający wczoraj, dramatycznie bardziej złożonym jutro? Co się zmieniło, że znacząca poprawa, przy zachowaniu prostoty, nie wystarczy – ale wymaga rzędów wielkości więcej złożoności i wydatków, które wcześniej nie były uzasadnione?”
To tylko typowe przykłady – złożoność istnieje w każdym aspekcie naszej branży. Szukaj prostoty. Dąż do elegancji. Nie akceptuj złożoności bez jej rygorystycznej weryfikacji. Przefiltruj ją przez przysłowiowe sito. Nie pozwól, by złożoność wkradała się tam, gdzie nie jest uzasadniona. Nie błądź w kierunku złożoności – w razie wątpliwości, wybierz prostą porażkę. Uproszczenie rozwiązania skutkuje zazwyczaj drobną awarią, podczas gdy nadmierne skomplikowanie dopuszcza znacznie większy zakres awarii. Bezpieczniejszym wyborem jest prostsze rozwiązanie. A jeśli proste rozwiązanie okaże się niewystarczające, znacznie łatwiej jest dodać złożoność, niż ją usunąć.
