Każdy ma taką inżynierię, na jaką go stać

Z powodów najróżniejszych, wśród których zmiana pracodawcy wcale nie jest najważniejszym, nie poświęcam ostatnio tyle uwagi okolicznym blogom, ile szanujący się obywatel Sieci poświęcać powinien. Jednak mimo przeciwności zdarza mi się trafić, zazwyczaj po czasie, na coś interesującego...

Na przykład blog patrys@pld-linux.org, a w nim wcale nie tak dawny wpis „Inżynieria nieprogramowania” zawierający (oprócz intrygującego tytułu) mnóstwo interesujących stwierdzeń, w tym:

w przypadku oprogramowania komercyjnego [...] pisanie własnego systemu powinno być ostatnim podejmowanym krokiem. [...] Pisanie oprogramowania, które nie będzie się nadawało do wdrożenia mija się z celem, tak samo jak napisanie od zera kolejnego pakietu o identycznej funkcjonalności. [...] Reasumując: w pracy codziennej pisze się masę nowego kodu, ale staramy się ograniczać do tego, którego napisanie jest nieodwołalne.

Patrys

Inżynieria nieprogramowania

a pod tym całą masę błyskotliwych komentarzy.

Łatwo ulec pokusie aby się z powyższym w pełni zgodzić. Pomysł, że praktycznie wszystko co ważne i istotne już zostało napisane i cała dzisiejsza produkcja oprogramowania to głównie składanie z gotowych klocków, jest faktycznie dosyć pociągający. Z czysto akademickiego punktu widzenia. Niestety, jak każdy teoretyczny punkt widzenia, ma to jedną malutką, acz wredną wadę — w ogóle nie przystaje do rzeczywistości.

Kilka dni temu, podczas przygotowywania wyceny pracochłonności pewnego sporego zadania, określając współczynnik TCF w arkuszu metody UCP przyjąłem w pozycjach T5 („Code must be reusable”) i T8 („Must be portable”) wartości zero (słownie: zero). Zrobiłem to całkowicie świadomie i z pełną premedytacją zakadając, że tworzony kod nie musi nadawać się do ponownego wykorzystania w ramach innego systemu, na innej platformie czy w ogóle w jakichkolwiek innych warunkach niż te, z myślą o których powstaje. Założenie takie tylko pozornie sugeruje, że mamy do czynienia z ignorantem i nie mówię tak dlatego, że osobiście jestem za nie odpowiedzialny... No może dlatego też, ale nie wyłącznie... ;-)

Wyobraźmy sobie sytuację, w której do napisania jest pewien moduł systemu, duży fragment, kluczowy wręcz, jednak jeszcze w docelowym systemie nie istniejący. Większość pozostałej części systemu już istnieje w postaci jakiejś, a w postaci docelowej będzie istnieć „za chwilę”. Jest to klasyczna sytuacja przerabiania „szarego na złote” czyli tworzenia nowego systemu na podstawie jakiegoś innego, który powstał wcześniej dla zupełnie innego klienta i na swoje nieszczęście ma z nowym pewien fragment wspólny. Dlaczego nie można wziąć tylko fragmentu starego systemu i użyć go w nowym — bo nie jest to system modułowy, przynajmniej nie wystarczająco. Dlaczego w ogóle nowy system jest oparty na starym, a nie napisany od nowa — bo idea, że jest to Dobry Pomysł i Szybsze Rozwiązanie była zbyt długo lansowana i teraz jest po prostu za późno. Do tego dochodzi kilka interesująco zagmatwanych powodów politycznych i w efekcie nowy system powstaje na monolitycznych gruzach starego. I do takiego systemu w fazie mocno opóźnionej należy dopisać jeszcze jeden moduł, który zupełnie przypadkowo okazuje się kluczowy i jako taki odłożony na sam koniec... Klasyka.

Powyższa sytuacja występuje w przyrodzie (przynajmniej w okolicach przesiąkniętych wonią grzęzawiska) znacznie częściej niż to przewidują teoretycy w swoich najgorszych koszmarach. I mówiąc wprost — trzeba być niepoważnym i nieodpowiedzialnym marzycielem, aby sądzić, że wspomniany moduł powstanie i będzie funkcjonował jako elegancka czarna skrzynka, którą będzie można w przyszłości wyjąć i po „zaadaptowaniu za pomocą minimalnych zmian” wstawić w dowolny inny system...

Oczywiście, że nie zakładam powstawania koszmarków niestrawnych do zrozumienia przez kogokolwiek poza ich autorem (i to nie później niż miesiąc po napisaniu). Jednak wspomniane wcześniej „Must be reusable” i „Must be portable” ustawiam na zero — nie pozwolę sobie żeby myślenie o takich cechach kodu opóźniło powstanie gotowego systemu choćby o dzień. I robię to z premedytacja i świadomości konsekwencji. Bowiem czym innym jest pisanie kodu łatwo używalnego w ramach jednego projektu, a zupełnie czym innym jest tworzenie gotowych klocków do wykorzystania w zupełnie innym otoczeniu przez kogokolwiek i kiedykolwiek.

Powiem to jeszcze raz, bo to ważne:

  • moduł używalny wielokrotnie przez różne osoby czy zespoły w kontekście jednego systemu, dla którego moduł ten powstał — tak, w granicach rozsądku,
  • moduł teoretycznie funkcjonujący autonomicznie i zassany do systemu z zupełnie innego otoczenia — na pewno nie.

Dlaczego? Bo po prostu nie warto. Żywe systemy informatyczne nie funkcjonują tak, jak tego chce teoria i spece od marketingu. Niezależnie od tego jak często będziemy słyszeć o ponownym wykorzystywaniu komponentów czy systemów powstających w zupełnie nowej postaci po „zaadaptowaniu za pomocą minimalnych zmian”, oprogramowanie nie jest i nie będzie budowlą z gotowych klocków. Zwłaszcza systemy tworzone na konkretne zamówienie, pod specyficzne wymagania, a takich jest w świecie rozwiązań komercyjnych ogromna większość.

Zresztą, mimo upływu czasu i rosnącej listy „sukcesów mimo wszystko” ;-) wciąż nie umiem się pozbyć wrażenia, że miałem rację pisząc kiedyś, że przemyślany projekt i dobry kod to często zbytek, na który nas zwyczajnie nie stać...

Komentarze

#1 | 2005.09.06 12:59 | str()

To ja może za kolegę po fachu (i domenie) odpowiem. Patrys jest webdeveloperem. Światek projektów webowych jest dość dobrze okodowany i albo 1. odkrywcze idee nie są wcale takie znowu odkrywcze, albo 2. opracowanie + okodowanie + naunmienie userów jak używać nowinki zajmuje dużo czasu i może być zakończone niepowodzeniem.
Patrys mówi o sposobie programowania, którego żaden phpdeveloper przy zmysłach sprawnych niezanegowałby. Jeden z klocków znakomicie pasujący do całej tej webukładanki to Smarty (wątek poboczny, ibidem). Można go nie lubieć, można mu zarzucać zbytnią kombajnowatość, ale nie można odmówić mu łatwości integracji. Kolejny obowiązkowy zestaw klocków to PEAR::DB lub inne ADOdb. Podobną łatwością użycia cechują się inne klocuszki z PEAR. W kontekście tych _bibliotek_ wypowiedź Patrysa jest dość prawdziwa (na oko w 82,3333% ;-)
Autentycznym bólem w inżynierii jest to, o czym piszesz, a Lessig mówi tak ładnie: to build upon past. Wykorzystanie istniejących rozwiązań poprzez wyrwanie ich z korzeniami i osadzenie w nowym kodzie jest znacznie bardziej bolesne, a efekt przypomina ten ze starego kawału o po^H^Hmilicjantach, którym dano deski z otworami i polecono do odpowiednich otworów wpasować klocki o właściwym kształcie (30% wykazało się niezwykłą rzutkością umysłu, pozostali niezwykłą siłą). W projektach webowych takie podejści może działać, a programy utajnionym paskudztwem w środku są traktowane mniej poważnie (tak zauważam) niż aplikacje standalone. Być to może, bierze się ono z faktu, że WWW jest traktowane z mniejszą powagą tak przez zleceniodawców ("my to program już mamy, teraz tylko chcemy stronkę") jak i wyrobników ("ot, stronka, jakiś poll, newsy, grafik flaszem podpicuje"). Być też może, że takie rozwiązania amputacyjno-renowacyjne mają rację bytu, bo program phpowy zaczyna pracę od nowa z każdym refreshem strony "z czystym kontem" biorąc pod uwagę tylko garstkę danych z tablicy $_REQUEST i efekty uboczne przemiału kodu przez interpreter są krótkotrwałe a cpu i pamięć tania.
Trudno traktować uwagi Patrysa o minimalnych zmianach adaptacyjnych jako psalm dla pokolenia młodych webdeveli. Już krótkie randezvous z przyzwoicie prowadzonym zespołem koderów obnaży prawdę, że do ponownego wykorzystania w danym przypadku może nadawać się jedynie pomysł - co jedynie potwierdza Twoją zera w T5 i T8.

 

Uwaga: Ze względu na bardzo intensywną działalność spambotów komentowanie zostało wyłączone po 60 dniach od opublikowania wpisu. Jeżeli faktycznie chcesz jeszcze skomentować skorzystaj ze strony kontaktowej.